diff --git a/include/mysql/service_wsrep.h b/include/mysql/service_wsrep.h index 30ed7246eac..8d132212d77 100644 --- a/include/mysql/service_wsrep.h +++ b/include/mysql/service_wsrep.h @@ -84,6 +84,7 @@ extern struct wsrep_service_st { my_bool (*wsrep_get_debug_func)(); void (*wsrep_commit_ordered_func)(MYSQL_THD thd); my_bool (*wsrep_thd_is_applying_func)(const MYSQL_THD thd); + ulong (*wsrep_OSU_method_get_func)(const MYSQL_THD thd); my_bool (*wsrep_thd_has_ignored_error_func)(const MYSQL_THD thd); void (*wsrep_thd_set_ignored_error_func)(MYSQL_THD thd, my_bool val); } *wsrep_service; @@ -126,9 +127,9 @@ extern struct wsrep_service_st { #define wsrep_get_debug() wsrep_service->wsrep_get_debug_func() #define wsrep_commit_ordered(T) wsrep_service->wsrep_commit_ordered_func(T) #define wsrep_thd_is_applying(T) wsrep_service->wsrep_thd_is_applying_func(T) +#define wsrep_OSU_method_get(T) wsrep_service->wsrep_OSU_method_get_func(T) #define wsrep_thd_has_ignored_error(T) wsrep_service->wsrep_thd_has_ignored_error_func(T) #define wsrep_thd_set_ignored_error(T,V) wsrep_service->wsrep_thd_set_ignored_error_func(T,V) - #else #define MYSQL_SERVICE_WSREP_STATIC_INCLUDED @@ -220,9 +221,8 @@ extern "C" my_bool wsrep_get_debug(); extern "C" void wsrep_commit_ordered(MYSQL_THD thd); extern "C" my_bool wsrep_thd_is_applying(const MYSQL_THD thd); - +extern "C" ulong wsrep_OSU_method_get(const MYSQL_THD thd); extern "C" my_bool wsrep_thd_has_ignored_error(const MYSQL_THD thd); extern "C" void wsrep_thd_set_ignored_error(MYSQL_THD thd, my_bool val); - #endif #endif /* MYSQL_SERVICE_WSREP_INCLUDED */ diff --git a/include/wsrep.h b/include/wsrep.h index dbdb746409b..f8a1863b966 100644 --- a/include/wsrep.h +++ b/include/wsrep.h @@ -19,18 +19,27 @@ #include #ifdef WITH_WSREP + #define IF_WSREP(A,B) A + #define DBUG_ASSERT_IF_WSREP(A) DBUG_ASSERT(A) #define WSREP_MYSQL_DB (char *)"mysql" + #define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) \ - if (WSREP_ON && WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) \ + if (WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) \ goto wsrep_error_label; -#define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_) \ +#define WSREP_TO_ISOLATION_BEGIN_CREATE(db_, table_, table_list_, create_info_) \ + if (WSREP(thd) && \ + wsrep_to_isolation_begin(thd, db_, table_, \ + table_list_, NULL, create_info_)) \ + goto wsrep_error_label; + +#define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_, create_info_) \ if (WSREP(thd) && wsrep_thd_is_local(thd) && \ wsrep_to_isolation_begin(thd, db_, table_, \ - table_list_, alter_info_)) \ + table_list_, alter_info_, create_info_)) \ goto wsrep_error_label; #define WSREP_TO_ISOLATION_END \ @@ -56,14 +65,12 @@ * (e.g. embedded) */ #define IF_WSREP(A,B) B -//#define DBUG_ASSERT_IF_WSREP(A) #define WSREP_DEBUG(...) -//#define WSREP_INFO(...) -//#define WSREP_WARN(...) #define WSREP_ERROR(...) #define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) do { } while(0) -#define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_) +#define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_, create_info_) #define WSREP_TO_ISOLATION_END +#define WSREP_TO_ISOLATION_BEGIN_CREATE(db_, table_, table_list_, create_info_) #define WSREP_TO_ISOLATION_BEGIN_WRTCHK(db_, table_, table_list_) #define WSREP_SYNC_WAIT(thd_, before_) #endif /* WITH_WSREP */ diff --git a/mysql-test/suite/galera/r/wsrep_strict_ddl.result b/mysql-test/suite/galera/r/wsrep_strict_ddl.result new file mode 100644 index 00000000000..6d25ec35549 --- /dev/null +++ b/mysql-test/suite/galera/r/wsrep_strict_ddl.result @@ -0,0 +1,194 @@ +connection node_2; +connection node_1; +call mtr.add_suppression("WSREP: ALTER TABLE isolation failure"); +connection node_1; +SET GLOBAL binlog_format='ROW'; +create table before_t1(a int, count int, b int, key(b)) engine=Aria; +INSERT INTO before_t1 values (1,1,1); +set @@global.wsrep_strict_ddl=ON; +select @@global.wsrep_strict_ddl; +@@global.wsrep_strict_ddl +1 +connection node_2; +set @@global.wsrep_strict_ddl=ON; +select @@global.wsrep_strict_ddl; +@@global.wsrep_strict_ddl +1 +connection node_1; +CREATE TABLE t1(a int) engine=Aria; +ERROR HY000: DDL-statement is forbidden as table storage engine does not support Galera replication +SHOW WARNINGS; +Level Code Message +Error 4165 DDL-statement is forbidden as table storage engine does not support Galera replication +Warning 1031 WSREP: wsrep_strict_ddl=true and storage engine does not support Galera replication. +connection node_2; +SHOW CREATE TABLE t1; +ERROR 42S02: Table 'test.t1' doesn't exist +connection node_1; +CREATE TABLE t2(a int not null primary key) engine=InnoDB; +ALTER TABLE t2 engine=MyISAM; +ERROR HY000: DDL-statement is forbidden as table storage engine does not support Galera replication +SHOW WARNINGS; +Level Code Message +Error 4165 DDL-statement is forbidden as table storage engine does not support Galera replication +Warning 1031 WSREP: wsrep_strict_ddl=true and storage engine does not support Galera replication. +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +connection node_2; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +connection node_1; +TRUNCATE TABLE before_t1; +ERROR HY000: DDL-statement is forbidden as table storage engine does not support Galera replication +SELECT * FROM before_t1; +a count b +1 1 1 +connection node_2; +SET SESSION wsrep_sync_wait=15; +SELECT @@wsrep_sync_wait; +@@wsrep_sync_wait +15 +SELECT * FROM before_t1; +a count b +connection node_1; +CREATE VIEW x1 AS SELECT * FROM before_t1; +ERROR HY000: DDL-statement is forbidden as table storage engine does not support Galera replication +SHOW CREATE VIEW x1; +ERROR 42S02: Table 'test.x1' doesn't exist +connection node_2; +SHOW CREATE VIEW x1; +ERROR 42S02: Table 'test.x1' doesn't exist +connection node_1; +CREATE DEFINER=`root`@`localhost` TRIGGER increment_before_t1 +AFTER INSERT ON before_t1 FOR EACH ROW +UPDATE before_t1 SET before_t1.count = before_t1.count+1; +ERROR HY000: DDL-statement is forbidden as table storage engine does not support Galera replication +SHOW CREATE TRIGGER increment_before_t1; +ERROR HY000: Trigger does not exist +connection node_2; +SHOW CREATE TRIGGER increment_before_t1; +ERROR HY000: Trigger does not exist +connection node_1; +CREATE INDEX xx2 ON before_t1(a); +ERROR HY000: DDL-statement is forbidden as table storage engine does not support Galera replication +SHOW CREATE TABLE before_t1; +Table Create Table +before_t1 CREATE TABLE `before_t1` ( + `a` int(11) DEFAULT NULL, + `count` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + KEY `b` (`b`) +) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 +connection node_2; +SHOW CREATE TABLE before_t1; +Table Create Table +before_t1 CREATE TABLE `before_t1` ( + `a` int(11) DEFAULT NULL, + `count` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + KEY `b` (`b`) +) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 +connection node_1; +DROP INDEX b ON before_t1; +ERROR HY000: DDL-statement is forbidden as table storage engine does not support Galera replication +SHOW CREATE TABLE before_t1; +Table Create Table +before_t1 CREATE TABLE `before_t1` ( + `a` int(11) DEFAULT NULL, + `count` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + KEY `b` (`b`) +) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 +connection node_2; +SHOW CREATE TABLE before_t1; +Table Create Table +before_t1 CREATE TABLE `before_t1` ( + `a` int(11) DEFAULT NULL, + `count` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + KEY `b` (`b`) +) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 +connection node_1; +ALTER TABLE before_t1 ADD COLUMN f int; +ERROR HY000: DDL-statement is forbidden as table storage engine does not support Galera replication +SHOW CREATE TABLE before_t1; +Table Create Table +before_t1 CREATE TABLE `before_t1` ( + `a` int(11) DEFAULT NULL, + `count` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + KEY `b` (`b`) +) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 +connection node_2; +SHOW CREATE TABLE before_t1; +Table Create Table +before_t1 CREATE TABLE `before_t1` ( + `a` int(11) DEFAULT NULL, + `count` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + KEY `b` (`b`) +) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 +connection node_1; +RENAME TABLE before_t1 to after_t1; +ERROR HY000: DDL-statement is forbidden as table storage engine does not support Galera replication +SHOW CREATE TABLE before_t1; +Table Create Table +before_t1 CREATE TABLE `before_t1` ( + `a` int(11) DEFAULT NULL, + `count` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + KEY `b` (`b`) +) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 +SHOW CREATE TABLE after_t1; +ERROR 42S02: Table 'test.after_t1' doesn't exist +connection node_2; +SHOW CREATE TABLE before_t1; +Table Create Table +before_t1 CREATE TABLE `before_t1` ( + `a` int(11) DEFAULT NULL, + `count` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + KEY `b` (`b`) +) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 +SHOW CREATE TABLE after_t1; +ERROR 42S02: Table 'test.after_t1' doesn't exist +connection node_1; +DROP TABLE before_t1; +ERROR HY000: DDL-statement is forbidden as table storage engine does not support Galera replication +SHOW CREATE TABLE before_t1; +Table Create Table +before_t1 CREATE TABLE `before_t1` ( + `a` int(11) DEFAULT NULL, + `count` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + KEY `b` (`b`) +) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 +connection node_2; +SHOW CREATE TABLE before_t1; +Table Create Table +before_t1 CREATE TABLE `before_t1` ( + `a` int(11) DEFAULT NULL, + `count` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + KEY `b` (`b`) +) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 +connection node_1; +set @@global.wsrep_strict_ddl=OFF; +select @@global.wsrep_strict_ddl; +@@global.wsrep_strict_ddl +0 +connection node_2; +set @@global.wsrep_strict_ddl=OFF; +select @@global.wsrep_strict_ddl; +@@global.wsrep_strict_ddl +0 +DROP TABLE t2; +DROP TABLE before_t1; diff --git a/mysql-test/suite/galera/t/wsrep_strict_ddl.test b/mysql-test/suite/galera/t/wsrep_strict_ddl.test new file mode 100644 index 00000000000..c0a0cd756ba --- /dev/null +++ b/mysql-test/suite/galera/t/wsrep_strict_ddl.test @@ -0,0 +1,133 @@ +--source include/galera_cluster.inc + +call mtr.add_suppression("WSREP: ALTER TABLE isolation failure"); + +--connection node_1 +SET GLOBAL binlog_format='ROW'; +create table before_t1(a int, count int, b int, key(b)) engine=Aria; +INSERT INTO before_t1 values (1,1,1); + +set @@global.wsrep_strict_ddl=ON; +select @@global.wsrep_strict_ddl; + +--connection node_2 +set @@global.wsrep_strict_ddl=ON; +select @@global.wsrep_strict_ddl; + +--connection node_1 +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +CREATE TABLE t1(a int) engine=Aria; +SHOW WARNINGS; + +--connection node_2 +--error ER_NO_SUCH_TABLE +SHOW CREATE TABLE t1; + +--connection node_1 +CREATE TABLE t2(a int not null primary key) engine=InnoDB; + +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +ALTER TABLE t2 engine=MyISAM; +SHOW WARNINGS; +SHOW CREATE TABLE t2; + +--connection node_2 +SHOW CREATE TABLE t2; + +--connection node_1 +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +TRUNCATE TABLE before_t1; +SELECT * FROM before_t1; + +--connection node_2 +SET SESSION wsrep_sync_wait=15; +SELECT @@wsrep_sync_wait; +SELECT * FROM before_t1; + +--connection node_1 +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +CREATE VIEW x1 AS SELECT * FROM before_t1; +--error ER_NO_SUCH_TABLE +SHOW CREATE VIEW x1; + +--connection node_2 +--error ER_NO_SUCH_TABLE +SHOW CREATE VIEW x1; + +--connection node_1 +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +CREATE DEFINER=`root`@`localhost` TRIGGER increment_before_t1 + AFTER INSERT ON before_t1 FOR EACH ROW + UPDATE before_t1 SET before_t1.count = before_t1.count+1; + +--error ER_TRG_DOES_NOT_EXIST +SHOW CREATE TRIGGER increment_before_t1; + +--connection node_2 + +--error ER_TRG_DOES_NOT_EXIST +SHOW CREATE TRIGGER increment_before_t1; + +--connection node_1 +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +CREATE INDEX xx2 ON before_t1(a); +SHOW CREATE TABLE before_t1; + +--connection node_2 +SHOW CREATE TABLE before_t1; + +--connection node_1 +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +DROP INDEX b ON before_t1; +SHOW CREATE TABLE before_t1; + +--connection node_2 +SHOW CREATE TABLE before_t1; + +--connection node_1 +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +ALTER TABLE before_t1 ADD COLUMN f int; +SHOW CREATE TABLE before_t1; + +--connection node_2 +SHOW CREATE TABLE before_t1; + +--connection node_1 +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +RENAME TABLE before_t1 to after_t1; +SHOW CREATE TABLE before_t1; +--error ER_NO_SUCH_TABLE +SHOW CREATE TABLE after_t1; + +--connection node_2 +SHOW CREATE TABLE before_t1; +--error ER_NO_SUCH_TABLE +SHOW CREATE TABLE after_t1; + +--connection node_1 +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +DROP TABLE before_t1; + +SHOW CREATE TABLE before_t1; + +--connection node_2 +SHOW CREATE TABLE before_t1; + +# +# PROCEDURE, EVENT, FUNCTION +# Unfortunately accessed tables are opened only +# in SP execution so no hope at CREATE + +# +# USER, ROLE, SERVER, DATABASE not really storage engine objects +# + +--connection node_1 +set @@global.wsrep_strict_ddl=OFF; +select @@global.wsrep_strict_ddl; + +--connectIon node_2 +set @@global.wsrep_strict_ddl=OFF; +select @@global.wsrep_strict_ddl; +DROP TABLE t2; +DROP TABLE before_t1; diff --git a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result index a1d66e4d112..328fa1fee16 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result +++ b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result @@ -706,6 +706,21 @@ ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED GLOBAL_VALUE_PATH NULL +VARIABLE_NAME WSREP_STRICT_DDL +SESSION_VALUE NULL +GLOBAL_VALUE OFF +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE OFF +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE BOOLEAN +VARIABLE_COMMENT Reject DDL on effected tables not supporting Galera replication +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST OFF,ON +READ_ONLY NO +COMMAND_LINE_ARGUMENT OPTIONAL +GLOBAL_VALUE_PATH NULL VARIABLE_NAME WSREP_SYNC_WAIT SESSION_VALUE 0 GLOBAL_VALUE 0 diff --git a/mysql-test/suite/sys_vars/r/wsrep_strict_ddl_basic.result b/mysql-test/suite/sys_vars/r/wsrep_strict_ddl_basic.result new file mode 100644 index 00000000000..6d686f9de2e --- /dev/null +++ b/mysql-test/suite/sys_vars/r/wsrep_strict_ddl_basic.result @@ -0,0 +1,45 @@ +# +# wsrep_strict_ddl +# +# save the initial value +SET @wsrep_strict_ddl_global_saved = @@global.wsrep_strict_ddl; +# default +SELECT @@global.wsrep_strict_ddl; +@@global.wsrep_strict_ddl +0 + +# scope +SELECT @@session.wsrep_strict_ddl; +ERROR HY000: Variable 'wsrep_strict_ddl' is a GLOBAL variable +SET @@global.wsrep_strict_ddl=OFF; +SELECT @@global.wsrep_strict_ddl; +@@global.wsrep_strict_ddl +0 +SET @@global.wsrep_strict_ddl=ON; +SELECT @@global.wsrep_strict_ddl; +@@global.wsrep_strict_ddl +1 + +# valid values +SET @@global.wsrep_strict_ddl='OFF'; +SELECT @@global.wsrep_strict_ddl; +@@global.wsrep_strict_ddl +0 +SET @@global.wsrep_strict_ddl=ON; +SELECT @@global.wsrep_strict_ddl; +@@global.wsrep_strict_ddl +1 +SET @@global.wsrep_strict_ddl=default; +SELECT @@global.wsrep_strict_ddl; +@@global.wsrep_strict_ddl +0 + +# invalid values +SET @@global.wsrep_strict_ddl=NULL; +ERROR 42000: Variable 'wsrep_strict_ddl' can't be set to the value of 'NULL' +SET @@global.wsrep_strict_ddl='junk'; +ERROR 42000: Variable 'wsrep_strict_ddl' can't be set to the value of 'junk' + +# restore the initial value +SET @@global.wsrep_strict_ddl = @wsrep_strict_ddl_global_saved; +# End of test diff --git a/mysql-test/suite/sys_vars/t/wsrep_strict_ddl_basic.test b/mysql-test/suite/sys_vars/t/wsrep_strict_ddl_basic.test new file mode 100644 index 00000000000..04d20ff3db5 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/wsrep_strict_ddl_basic.test @@ -0,0 +1,42 @@ +--source include/have_wsrep.inc + +--echo # +--echo # wsrep_strict_ddl +--echo # + +--echo # save the initial value +SET @wsrep_strict_ddl_global_saved = @@global.wsrep_strict_ddl; + +--echo # default +SELECT @@global.wsrep_strict_ddl; + +--echo +--echo # scope +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.wsrep_strict_ddl; +SET @@global.wsrep_strict_ddl=OFF; +SELECT @@global.wsrep_strict_ddl; +SET @@global.wsrep_strict_ddl=ON; +SELECT @@global.wsrep_strict_ddl; + +--echo +--echo # valid values +SET @@global.wsrep_strict_ddl='OFF'; +SELECT @@global.wsrep_strict_ddl; +SET @@global.wsrep_strict_ddl=ON; +SELECT @@global.wsrep_strict_ddl; +SET @@global.wsrep_strict_ddl=default; +SELECT @@global.wsrep_strict_ddl; + +--echo +--echo # invalid values +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_strict_ddl=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_strict_ddl='junk'; + +--echo +--echo # restore the initial value +SET @@global.wsrep_strict_ddl = @wsrep_strict_ddl_global_saved; + +--echo # End of test diff --git a/sql/service_wsrep.cc b/sql/service_wsrep.cc index 68de55b5778..8a547710143 100644 --- a/sql/service_wsrep.cc +++ b/sql/service_wsrep.cc @@ -52,13 +52,14 @@ extern "C" const char* wsrep_thd_transaction_state_str(const THD *thd) return wsrep::to_c_string(thd->wsrep_cs().transaction().state()); } - extern "C" const char *wsrep_thd_query(const THD *thd) { - if (thd) + if (!thd) + return "NULL"; + + switch(thd->lex->sql_command) { - switch(thd->lex->sql_command) - { + // Mask away some security related details from error log case SQLCOM_CREATE_USER: return "CREATE USER"; case SQLCOM_GRANT: @@ -67,12 +68,10 @@ extern "C" const char *wsrep_thd_query(const THD *thd) return "REVOKE"; case SQLCOM_SET_OPTION: if (thd->lex->definer) - return "SET PASSWORD"; + return "SET PASSWORD"; /* fallthrough */ default: - if (thd->query()) - return thd->query(); - } + return (thd->query() ? thd->query() : "NULL"); } return "NULL"; } @@ -321,3 +320,11 @@ extern "C" void wsrep_thd_set_ignored_error(THD *thd, my_bool val) { thd->wsrep_has_ignored_error= val; } + +extern "C" ulong wsrep_OSU_method_get(const MYSQL_THD thd) +{ + if (thd) + return(thd->variables.wsrep_OSU_method); + else + return(global_system_variables.wsrep_OSU_method); +} diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index dbff2b204d8..78b6cfa63c8 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7943,3 +7943,5 @@ ER_WARN_HISTORY_ROW_START_TIME eng "Table `%s.%s` history row start '%s' is later than row end '%s'" ER_PART_STARTS_BEYOND_INTERVAL eng "%`s: STARTS is later than query time, first history partition may exceed INTERVAL value" +ER_GALERA_REPLICATION_NOT_SUPPORTED + eng "DDL-statement is forbidden as table storage engine does not support Galera replication" \ No newline at end of file diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index f3dd46b5139..0828e1b7ba8 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -505,9 +505,9 @@ bool Sql_cmd_alter_table::execute(THD *thd) (!thd->is_current_stmt_binlog_format_row() || !thd->find_temporary_table(first_table))) { - WSREP_TO_ISOLATION_BEGIN_ALTER((lex->name.str ? select_lex->db.str : NULL), - (lex->name.str ? lex->name.str : NULL), - first_table, &alter_info); + WSREP_TO_ISOLATION_BEGIN_ALTER((lex->name.str ? select_lex->db.str : first_table->db.str), + (lex->name.str ? lex->name.str : first_table->table_name.str), + first_table, &alter_info, used_engine ? &create_info : NULL); thd->variables.auto_increment_offset = 1; thd->variables.auto_increment_increment = 1; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 141dfd9be65..e8b5e319773 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3079,6 +3079,7 @@ mysql_create_routine(THD *thd, LEX *lex) return true; WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + if (!lex->sphead->m_handler->sp_create_routine(thd, lex->sphead)) { #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -4147,7 +4148,6 @@ mysql_execute_command(THD *thd) DBUG_ASSERT(first_table == all_tables && first_table != 0); if (check_one_table_access(thd, INDEX_ACL, all_tables)) goto error; /* purecov: inspected */ - WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL); bzero((char*) &create_info, sizeof(create_info)); create_info.db_type= 0; @@ -4155,6 +4155,8 @@ mysql_execute_command(THD *thd) create_info.default_table_charset= thd->variables.collation_database; create_info.alter_info= &alter_info; + WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL); + res= mysql_alter_table(thd, &first_table->db, &first_table->table_name, &create_info, first_table, &alter_info, 0, (ORDER*) 0, 0); @@ -4857,6 +4859,7 @@ mysql_execute_command(THD *thd) slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT) lex->create_info.set(DDL_options_st::OPT_IF_EXISTS); +#ifdef WITH_WSREP if (WSREP(thd)) { for (TABLE_LIST *table= all_tables; table; table= table->next_global) @@ -4870,7 +4873,8 @@ mysql_execute_command(THD *thd) } } } - +#endif /* WITH_WSREP */ + /* DDL and binlog write order are protected by metadata locks. */ res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table(), lex->table_type == TABLE_TYPE_SEQUENCE); @@ -5070,7 +5074,9 @@ mysql_execute_command(THD *thd) (CREATE_ACL | DROP_ACL) : CREATE_ACL, &lex->name)) break; + WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL); + res= mysql_create_db(thd, &lex->name, lex->create_info, &lex->create_info); break; @@ -5079,7 +5085,9 @@ mysql_execute_command(THD *thd) { if (prepare_db_action(thd, DROP_ACL, &lex->name)) break; + WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL); + res= mysql_rm_db(thd, &lex->name, lex->if_exists()); break; } @@ -5111,7 +5119,9 @@ mysql_execute_command(THD *thd) res= 1; break; } + WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL); + res= mysql_upgrade_db(thd, db); if (!res) my_ok(thd); @@ -5122,7 +5132,9 @@ mysql_execute_command(THD *thd) LEX_CSTRING *db= &lex->name; if (prepare_db_action(thd, ALTER_ACL, db)) break; + WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL); + res= mysql_alter_db(thd, db, &lex->create_info); break; } @@ -5196,6 +5208,7 @@ mysql_execute_command(THD *thd) break; #ifdef HAVE_DLOPEN WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + if (!(res = mysql_create_function(thd, &lex->udf))) my_ok(thd); #else @@ -5213,7 +5226,9 @@ mysql_execute_command(THD *thd) "mysql", NULL, NULL, 1, 1) && check_global_access(thd,CREATE_USER_ACL)) break; + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + /* Conditionally writes to binlog */ if (!(res= mysql_create_user(thd, lex->users_list, lex->sql_command == SQLCOM_CREATE_ROLE))) @@ -5226,8 +5241,10 @@ mysql_execute_command(THD *thd) if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 1) && check_global_access(thd,CREATE_USER_ACL)) break; - /* Conditionally writes to binlog */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + + /* Conditionally writes to binlog */ if (!(res= mysql_drop_user(thd, lex->users_list, lex->sql_command == SQLCOM_DROP_ROLE))) my_ok(thd); @@ -5239,8 +5256,10 @@ mysql_execute_command(THD *thd) if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 1) && check_global_access(thd,CREATE_USER_ACL)) break; - /* Conditionally writes to binlog */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + + /* Conditionally writes to binlog */ if (lex->sql_command == SQLCOM_ALTER_USER) res= mysql_alter_user(thd, lex->users_list); else @@ -5255,16 +5274,19 @@ mysql_execute_command(THD *thd) check_global_access(thd,CREATE_USER_ACL)) break; - /* Conditionally writes to binlog */ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + + /* Conditionally writes to binlog */ if (!(res = mysql_revoke_all(thd, lex->users_list))) my_ok(thd); break; } + case SQLCOM_REVOKE_ROLE: case SQLCOM_GRANT_ROLE: { WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + if (!(res= mysql_grant_role(thd, lex->users_list, lex->sql_command != SQLCOM_GRANT_ROLE))) my_ok(thd); @@ -5611,6 +5633,7 @@ mysql_execute_command(THD *thd) case SQLCOM_DROP_PACKAGE: case SQLCOM_DROP_PACKAGE_BODY: if (drop_routine(thd, lex)) + goto error; break; case SQLCOM_SHOW_CREATE_PROC: @@ -5676,8 +5699,10 @@ mysql_execute_command(THD *thd) { if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE)) goto error; - /* Conditionally writes to binlog. */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + + /* Conditionally writes to binlog. */ res= mysql_drop_view(thd, first_table, thd->lex->drop_mode); break; } @@ -5983,7 +6008,7 @@ finish: #ifdef WITH_WSREP thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK; - + WSREP_TO_ISOLATION_END; /* Force release of transactional locks if not in active MST and wsrep is on. diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic index 3faabcf5032..2db426e7b57 100644 --- a/sql/sql_plugin_services.ic +++ b/sql/sql_plugin_services.ic @@ -175,6 +175,7 @@ static struct wsrep_service_st wsrep_handler = { wsrep_get_debug, wsrep_commit_ordered, wsrep_thd_is_applying, + wsrep_OSU_method_get, wsrep_thd_has_ignored_error, wsrep_thd_set_ignored_error }; diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 1c6cf52963a..8f818e321dd 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -286,6 +286,13 @@ do_rename(THD *thd, TABLE_LIST *ren_table, const LEX_CSTRING *new_db, if (ha_table_exists(thd, &ren_table->db, &old_alias, &hton) && hton) { DBUG_ASSERT(!thd->locked_tables_mode); + +#ifdef WITH_WSREP + if (WSREP(thd) && hton && + !wsrep_should_replicate_ddl(thd, hton->db_type)) + DBUG_RETURN(1); +#endif + tdc_remove_table(thd, TDC_RT_REMOVE_ALL, ren_table->db.str, ren_table->table_name.str); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e4a33dd99cd..240f001f7de 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2443,6 +2443,16 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, { char *end; int frm_delete_error= 0; + +#ifdef WITH_WSREP + if (WSREP(thd) && + !wsrep_should_replicate_ddl(thd, table_type->db_type)) + { + error= 1; + goto err; + } +#endif + /* It could happen that table's share in the table definition cache is the only thing that keeps the engine plugin loaded @@ -9461,6 +9471,17 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, &alter_prelocking_strategy); thd->open_options&= ~HA_OPEN_FOR_ALTER; +#ifdef WITH_WSREP + if (WSREP(thd) && + (thd->lex->sql_command == SQLCOM_ALTER_TABLE || + thd->lex->sql_command == SQLCOM_CREATE_INDEX || + thd->lex->sql_command == SQLCOM_DROP_INDEX) && + !wsrep_should_replicate_ddl(thd, table_list->table->s->db_type()->db_type)) + DBUG_RETURN(true); +#endif + + DEBUG_SYNC(thd, "alter_table_after_open_tables"); + TABLE *table= table_list->table; bool versioned= table && table->versioned(); @@ -11503,7 +11524,8 @@ bool Sql_cmd_create_table_like::execute(THD *thd) (!thd->is_current_stmt_binlog_format_row() || !create_info.tmp_table())) { - WSREP_TO_ISOLATION_BEGIN(create_table->db.str, create_table->table_name.str, NULL); + WSREP_TO_ISOLATION_BEGIN_CREATE(create_table->db.str, create_table->table_name.str, + create_table, &create_info); } /* Regular CREATE TABLE */ res= mysql_create_table(thd, create_table, &create_info, &alter_info); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 5802d2c811e..0ae3d58b11f 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -507,9 +507,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) goto end; } -#ifdef WITH_WSREP WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, tables); -#endif /* We should have only one table in table list. */ DBUG_ASSERT(tables->next_global == 0); @@ -550,6 +548,12 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) } table= tables->table; +#ifdef WITH_WSREP + if (WSREP(thd) && + !wsrep_should_replicate_ddl(thd, table->s->db_type()->db_type)) + goto wsrep_error_label; +#endif + /* Later on we will need it to downgrade the lock */ mdl_ticket= table->mdl_ticket; diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 8e078ff02af..a47822e43ca 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -303,6 +303,12 @@ bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref, versioned= table->versioned(); hton= table->file->ht; +#ifdef WITH_WSREP + if (WSREP(thd) && + !wsrep_should_replicate_ddl(thd, hton->db_type)) + DBUG_RETURN(TRUE); +#endif + table_ref->mdl_request.ticket= table->mdl_ticket; } else @@ -320,6 +326,15 @@ bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref, versioned= share->versioned; sequence= share->table_type == TABLE_TYPE_SEQUENCE; hton= share->db_type(); +#ifdef WITH_WSREP + if (WSREP(thd) && + hton != view_pseudo_hton && + !wsrep_should_replicate_ddl(thd, hton->db_type)) + { + tdc_release_share(share); + DBUG_RETURN(TRUE); + } +#endif tdc_release_share(share); @@ -417,9 +432,10 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) #ifdef WITH_WSREP if (WSREP(thd) && - wsrep_to_isolation_begin(thd, table_ref->db.str, table_ref->table_name.str, 0)) - DBUG_RETURN(TRUE); + wsrep_to_isolation_begin(thd, table_ref->db.str, table_ref->table_name.str, NULL)) + DBUG_RETURN(TRUE); #endif /* WITH_WSREP */ + if (lock_table(thd, table_ref, &hton_can_recreate)) DBUG_RETURN(TRUE); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 12dfb8bc59d..f47e910c0fe 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -37,6 +37,7 @@ #include "sql_derived.h" #include "sql_cte.h" // check_dependencies_in_with_clauses() #include "opt_trace.h" +#include "wsrep_mysqld.h" #define MD5_BUFF_LENGTH 33 @@ -454,6 +455,14 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, goto err; } +#ifdef WITH_WSREP + if(!wsrep_should_replicate_ddl_iterate(thd, static_cast(tables))) + { + res= TRUE; + goto err; + } +#endif + view= lex->unlink_first_table(&link_to_local); if (check_db_dir_existence(view->db.str)) diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index ab382304973..4dfec12ee29 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -5685,12 +5685,20 @@ static Sys_var_enum Sys_wsrep_OSU_method( static PolyLock_mutex PLock_wsrep_desync(&LOCK_wsrep_desync); static Sys_var_mybool Sys_wsrep_desync ( "wsrep_desync", "To desynchronize the node from the cluster", - GLOBAL_VAR(wsrep_desync), + GLOBAL_VAR(wsrep_desync), CMD_LINE(OPT_ARG), DEFAULT(FALSE), &PLock_wsrep_desync, NOT_IN_BINLOG, ON_CHECK(wsrep_desync_check), ON_UPDATE(wsrep_desync_update)); +static Sys_var_mybool Sys_wsrep_strict_ddl ( + "wsrep_strict_ddl", "Reject DDL on effected tables not supporting Galera replication", + GLOBAL_VAR(wsrep_strict_ddl), + CMD_LINE(OPT_ARG), DEFAULT(FALSE), + NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(0), + ON_UPDATE(0)); + static const char *wsrep_reject_queries_names[]= { "NONE", "ALL", "ALL_KILL", NullS }; static Sys_var_enum Sys_wsrep_reject_queries( "wsrep_reject_queries", "Variable to set to reject queries", diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc index b87e807c7c9..ffc6acc8bd9 100644 --- a/sql/wsrep_dummy.cc +++ b/sql/wsrep_dummy.cc @@ -144,3 +144,5 @@ my_bool wsrep_thd_has_ignored_error(const THD*) void wsrep_thd_set_ignored_error(THD*, my_bool) { } +ulong wsrep_OSU_method_get(const THD*) +{ return 0;} \ No newline at end of file diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index a3c5e91eb24..ff01473e816 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -96,6 +96,9 @@ my_bool wsrep_restart_slave; // Should mysql slave thread be // restarted, when node joins back? my_bool wsrep_desync; // De(re)synchronize the node from the // cluster +my_bool wsrep_strict_ddl; // Reject DDL to + // effected tables not + // supporting Galera replication long wsrep_slave_threads; // No. of slave appliers threads ulong wsrep_retry_autocommit; // Retry aborted autocommit trx ulong wsrep_max_ws_size; // Max allowed ws (RBR buffer) size @@ -1296,11 +1299,11 @@ static bool wsrep_prepare_key_for_isolation(const char* db, } static bool wsrep_prepare_keys_for_alter_add_fk(const char* child_table_db, - Alter_info* alter_info, + const Alter_info* alter_info, wsrep_key_arr_t* ka) { Key *key; - List_iterator key_iterator(alter_info->key_list); + List_iterator key_iterator(const_cast(alter_info)->key_list); while ((key= key_iterator++)) { if (key->type == Key::FOREIGN_KEY) @@ -1436,12 +1439,12 @@ wsrep::key wsrep_prepare_key_for_toi(const char* db, const char* table, wsrep::key_array wsrep_prepare_keys_for_alter_add_fk(const char* child_table_db, - Alter_info* alter_info) + const Alter_info* alter_info) { wsrep::key_array ret; Key *key; - List_iterator key_iterator(alter_info->key_list); + List_iterator key_iterator(const_cast(alter_info)->key_list); while ((key= key_iterator++)) { if (key->type == Key::FOREIGN_KEY) @@ -1463,7 +1466,7 @@ wsrep_prepare_keys_for_alter_add_fk(const char* child_table_db, wsrep::key_array wsrep_prepare_keys_for_toi(const char* db, const char* table, const TABLE_LIST* table_list, - Alter_info* alter_info) + const Alter_info* alter_info) { wsrep::key_array ret; if (db || table) @@ -1735,6 +1738,51 @@ static int wsrep_drop_table_query(THD* thd, uchar** buf, size_t* buf_len) /* Forward declarations. */ int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len); +bool wsrep_should_replicate_ddl_iterate(THD* thd, const TABLE_LIST* table_list) +{ + if (WSREP(thd)) + { + for (const TABLE_LIST* it= table_list; it; it= it->next_global) + { + if (!wsrep_should_replicate_ddl(thd, it->table->s->db_type()->db_type)) + return false; + } + } + return true; +} + +bool wsrep_should_replicate_ddl(THD* thd, + const enum legacy_db_type db_type) +{ + if (!wsrep_strict_ddl) + return true; + + switch (db_type) + { + case DB_TYPE_INNODB: + return true; + break; + case DB_TYPE_MYISAM: + if (wsrep_replicate_myisam) + return true; + else + WSREP_DEBUG("wsrep OSU failed for %s", wsrep_thd_query(thd)); + break; + case DB_TYPE_ARIA: + /* if (wsrep_replicate_aria) */ + /* fallthrough */ + default: + WSREP_DEBUG("wsrep OSU failed for %s", wsrep_thd_query(thd)); + break; + } + + /* STRICT, treat as error */ + my_error(ER_GALERA_REPLICATION_NOT_SUPPORTED, MYF(0)); + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_ILLEGAL_HA, + "WSREP: wsrep_strict_ddl=true and storage engine does not support Galera replication."); + return false; +} /* Decide if statement should run in TOI. @@ -1745,24 +1793,28 @@ int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len); should be rewritten at later time for replication to contain only non-temporary tables. */ -static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, - const TABLE_LIST *table_list) +bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, + const TABLE_LIST *table_list, + const HA_CREATE_INFO* create_info) { DBUG_ASSERT(!table || db); DBUG_ASSERT(table_list || db); LEX* lex= thd->lex; SELECT_LEX* select_lex= lex->first_select_lex(); - TABLE_LIST* first_table= select_lex->table_list.first; + const TABLE_LIST* first_table= select_lex->table_list.first; switch (lex->sql_command) { case SQLCOM_CREATE_TABLE: - DBUG_ASSERT(!table_list); if (thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) { return false; } + if (!wsrep_should_replicate_ddl(thd, create_info->db_type->db_type)) + { + return false; + } /* If mariadb master has replicated a CTAS, we should not replicate the create table part separately as TOI, but to replicate both create table and following inserts @@ -1771,7 +1823,8 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, as TOI. We have to do relay log event lookup to see if row events follow the create table event. */ - if (thd->slave_thread && !(thd->rgi_slave->gtid_ev_flags2 & Gtid_log_event::FL_STANDALONE)) + if (thd->slave_thread && + !(thd->rgi_slave->gtid_ev_flags2 & Gtid_log_event::FL_STANDALONE)) { /* this is CTAS, either empty or populated table */ ulonglong event_size = 0; @@ -1797,7 +1850,7 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, } /* no next async replication event */ return true; - + break; case SQLCOM_CREATE_VIEW: DBUG_ASSERT(!table_list); @@ -1806,7 +1859,7 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, If any of the remaining tables refer to temporary table error is returned to client, so TOI can be skipped */ - for (TABLE_LIST* it= first_table->next_global; it; it= it->next_global) + for (const TABLE_LIST* it= first_table->next_global; it; it= it->next_global) { if (thd->find_temporary_table(it)) { @@ -1814,7 +1867,7 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, } } return true; - + break; case SQLCOM_CREATE_TRIGGER: DBUG_ASSERT(first_table); @@ -1824,15 +1877,12 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, return false; } return true; - - case SQLCOM_DROP_TRIGGER: - DBUG_ASSERT(table_list); - if (thd->find_temporary_table(table_list)) - { + break; + case SQLCOM_ALTER_TABLE: + if (create_info && + !wsrep_should_replicate_ddl(thd, create_info->db_type->db_type)) return false; - } - return true; - + /* fallthrough */ default: if (table && !thd->find_temporary_table(db, table)) { @@ -1841,7 +1891,7 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, if (table_list) { - for (TABLE_LIST* table= first_table; table; table= table->next_global) + for (const TABLE_LIST* table= first_table; table; table= table->next_global) { if (!thd->find_temporary_table(table->db.str, table->table_name.str)) { @@ -1849,11 +1899,12 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, } } } + return !(table || table_list); + break; } } - static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len) { String log_query; @@ -1962,14 +2013,16 @@ fail: */ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, const TABLE_LIST* table_list, - Alter_info* alter_info) + const Alter_info* alter_info, + const HA_CREATE_INFO* create_info) { - DBUG_ASSERT(thd->variables.wsrep_OSU_method == WSREP_OSU_TOI); + DBUG_ASSERT(wsrep_OSU_method_get(thd) == WSREP_OSU_TOI); - WSREP_DEBUG("TOI Begin"); - if (wsrep_can_run_in_toi(thd, db, table, table_list) == false) + WSREP_DEBUG("TOI Begin: %s", wsrep_thd_query(thd)); + + if (wsrep_can_run_in_toi(thd, db, table, table_list, create_info) == false) { - WSREP_DEBUG("No TOI for %s", WSREP_QUERY(thd)); + WSREP_DEBUG("No TOI for %s", wsrep_thd_query(thd)); return 1; } @@ -1979,6 +2032,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, int rc; buf_err= wsrep_TOI_event_buf(thd, &buf, &buf_len); + if (buf_err) { WSREP_ERROR("Failed to create TOI event buf: %d", buf_err); my_message(ER_UNKNOWN_ERROR, @@ -1987,6 +2041,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, MYF(0)); return -1; } + struct wsrep_buf buff= { buf, buf_len }; wsrep::key_array key_array= @@ -1997,7 +2052,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, /* non replicated DDL, affecting temporary tables only */ WSREP_DEBUG("TO isolation skipped, sql: %s." "Only temporary tables affected.", - WSREP_QUERY(thd)); + wsrep_thd_query(thd)); if (buf) my_free(buf); return -1; } @@ -2005,6 +2060,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, thd_proc_info(thd, "acquiring total order isolation"); wsrep::client_state& cs(thd->wsrep_cs()); + int ret= cs.enter_toi_local(key_array, wsrep::const_buffer(buff.ptr, buff.len)); @@ -2012,7 +2068,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, { DBUG_ASSERT(cs.current_error()); WSREP_DEBUG("to_execute_start() failed for %llu: %s, seqno: %lld", - thd->thread_id, WSREP_QUERY(thd), + thd->thread_id, wsrep_thd_query(thd), (long long)wsrep_thd_trx_seqno(thd)); /* jump to error handler in mysql_execute_command() */ @@ -2023,7 +2079,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, "Maximum size exceeded.", ret, (thd->db.str ? thd->db.str : "(null)"), - WSREP_QUERY(thd)); + wsrep_thd_query(thd)); my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_SIZE_EXCEEDED); break; default: @@ -2031,7 +2087,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, "Check wsrep connection state and retry the query.", ret, (thd->db.str ? thd->db.str : "(null)"), - WSREP_QUERY(thd)); + wsrep_thd_query(thd)); if (!thd->is_error()) { my_error(ER_LOCK_DEADLOCK, MYF(0), "WSREP replication failed. Check " @@ -2079,7 +2135,7 @@ static void wsrep_TOI_end(THD *thd) { wsrep::client_state& client_state(thd->wsrep_cs()); DBUG_ASSERT(wsrep_thd_is_local_toi(thd)); WSREP_DEBUG("TO END: %lld: %s", client_state.toi_meta().seqno().get(), - WSREP_QUERY(thd)); + wsrep_thd_query(thd)); wsrep_gtid_server.signal_waiters(thd->wsrep_current_gtid_seqno, false); @@ -2104,7 +2160,7 @@ static void wsrep_TOI_end(THD *thd) { else { WSREP_WARN("TO isolation end failed for: %d, schema: %s, sql: %s", - ret, (thd->db.str ? thd->db.str : "(null)"), WSREP_QUERY(thd)); + ret, (thd->db.str ? thd->db.str : "(null)"), wsrep_thd_query(thd)); } } } @@ -2112,7 +2168,7 @@ static void wsrep_TOI_end(THD *thd) { static int wsrep_RSU_begin(THD *thd, const char *db_, const char *table_) { WSREP_DEBUG("RSU BEGIN: %lld, : %s", wsrep_thd_trx_seqno(thd), - WSREP_QUERY(thd)); + wsrep_thd_query(thd)); if (thd->wsrep_cs().begin_rsu(5000)) { WSREP_WARN("RSU begin failed"); @@ -2127,7 +2183,7 @@ static int wsrep_RSU_begin(THD *thd, const char *db_, const char *table_) static void wsrep_RSU_end(THD *thd) { WSREP_DEBUG("RSU END: %lld : %s", wsrep_thd_trx_seqno(thd), - WSREP_QUERY(thd)); + wsrep_thd_query(thd)); if (thd->wsrep_cs().end_rsu()) { WSREP_WARN("Failed to end RSU, server may need to be restarted"); @@ -2137,7 +2193,8 @@ static void wsrep_RSU_end(THD *thd) int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_, const TABLE_LIST* table_list, - Alter_info* alter_info) + const Alter_info* alter_info, + const HA_CREATE_INFO* create_info) { /* No isolation for applier or replaying threads. @@ -2162,14 +2219,14 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_, if (thd->global_read_lock.is_acquired()) { WSREP_DEBUG("Aborting TOI: Global Read-Lock (FTWRL) in place: %s %llu", - WSREP_QUERY(thd), thd->thread_id); + wsrep_thd_query(thd), thd->thread_id); return -1; } if (wsrep_debug && thd->mdl_context.has_locks()) { WSREP_DEBUG("thread holds MDL locks at TI begin: %s %llu", - WSREP_QUERY(thd), thd->thread_id); + wsrep_thd_query(thd), thd->thread_id); } /* @@ -2187,24 +2244,24 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_, if (thd->variables.wsrep_on && wsrep_thd_is_local(thd)) { - switch (thd->variables.wsrep_OSU_method) { + switch (wsrep_OSU_method_get(thd)) { case WSREP_OSU_TOI: - ret= wsrep_TOI_begin(thd, db_, table_, table_list, alter_info); + ret= wsrep_TOI_begin(thd, db_, table_, table_list, alter_info, create_info); break; case WSREP_OSU_RSU: ret= wsrep_RSU_begin(thd, db_, table_); break; default: WSREP_ERROR("Unsupported OSU method: %lu", - thd->variables.wsrep_OSU_method); + wsrep_OSU_method_get(thd)); ret= -1; break; } switch (ret) { - case 0: /* wsrep_TOI_begin sould set toi mode */ break; + case 0: /* wsrep_TOI_begin should set toi mode */ break; case 1: - /* TOI replication skipped, treat as success */ - ret= 0; + /* TOI replication skipped, treat as success */ + ret= 0; break; case -1: /* TOI replication failed, treat as error */ @@ -2221,12 +2278,12 @@ void wsrep_to_isolation_end(THD *thd) wsrep_thd_is_in_rsu(thd)); if (wsrep_thd_is_local_toi(thd)) { - DBUG_ASSERT(thd->variables.wsrep_OSU_method == WSREP_OSU_TOI); + DBUG_ASSERT(wsrep_OSU_method_get(thd) == WSREP_OSU_TOI); wsrep_TOI_end(thd); } else if (wsrep_thd_is_in_rsu(thd)) { - DBUG_ASSERT(thd->variables.wsrep_OSU_method == WSREP_OSU_RSU); + DBUG_ASSERT(wsrep_OSU_method_get(thd) == WSREP_OSU_RSU); wsrep_RSU_end(thd); } else @@ -2678,17 +2735,17 @@ bool wsrep_create_like_table(THD* thd, TABLE_LIST* table, if (create_info->tmp_table()) { /* CREATE TEMPORARY TABLE LIKE must be skipped from replication */ - WSREP_DEBUG("CREATE TEMPORARY TABLE LIKE... skipped replication\n %s", + WSREP_DEBUG("CREATE TEMPORARY TABLE LIKE... skipped replication\n %s", thd->query()); } else if (!(thd->find_temporary_table(src_table))) { /* this is straight CREATE TABLE LIKE... with no tmp tables */ - WSREP_TO_ISOLATION_BEGIN(table->db.str, table->table_name.str, NULL); + WSREP_TO_ISOLATION_BEGIN_CREATE(table->db.str, table->table_name.str, table, create_info); } else { - /* here we have CREATE TABLE LIKE + /* here we have CREATE TABLE LIKE the temporary table definition will be needed in slaves to enable the create to succeed */ @@ -2707,7 +2764,7 @@ bool wsrep_create_like_table(THD* thd, TABLE_LIST* table, thd->wsrep_TOI_pre_query= query.ptr(); thd->wsrep_TOI_pre_query_len= query.length(); - WSREP_TO_ISOLATION_BEGIN(table->db.str, table->table_name.str, NULL); + WSREP_TO_ISOLATION_BEGIN_CREATE(table->db.str, table->table_name.str, table, create_info); thd->wsrep_TOI_pre_query= NULL; thd->wsrep_TOI_pre_query_len= 0; diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 077e5602025..b51dc308646 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -98,6 +98,7 @@ extern ulong wsrep_running_applier_threads; extern ulong wsrep_running_rollbacker_threads; extern bool wsrep_new_cluster; extern bool wsrep_gtid_mode; +extern my_bool wsrep_strict_ddl; enum enum_wsrep_reject_types { WSREP_REJECT_NONE, /* nothing rejected */ @@ -108,7 +109,7 @@ enum enum_wsrep_reject_types { enum enum_wsrep_OSU_method { WSREP_OSU_TOI, WSREP_OSU_RSU, - WSREP_OSU_NONE, + WSREP_OSU_NONE }; enum enum_wsrep_sync_wait { @@ -360,9 +361,15 @@ extern PSI_thread_key key_wsrep_sst_donor_monitor; struct TABLE_LIST; class Alter_info; +struct HA_CREATE_INFO; + int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_, const TABLE_LIST* table_list, - Alter_info* alter_info= NULL); + const Alter_info* alter_info= NULL, + const HA_CREATE_INFO* create_info= NULL); + +bool wsrep_should_replicate_ddl(THD* thd, const enum legacy_db_type db_type); +bool wsrep_should_replicate_ddl_iterate(THD* thd, const TABLE_LIST* table_list); void wsrep_to_isolation_end(THD *thd);