From 45236704e871fcd9a23887464a8ff934c827b84f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 28 Feb 2014 21:46:43 +0100 Subject: [PATCH 01/11] update InnoDB version --- storage/innobase/include/univ.i | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index a4d292b4f0f..9b5fffe81e8 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -44,7 +44,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 5 #define INNODB_VERSION_MINOR 6 -#define INNODB_VERSION_BUGFIX 14 +#define INNODB_VERSION_BUGFIX 15 /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; From 8dce8ecfda303e15daf2832d90de024a6acf8e7e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 1 Mar 2014 10:19:42 +0100 Subject: [PATCH 02/11] minor cleanup --- strings/ctype-bin.c | 15 ++++++--------- strings/ctype-mb.c | 8 +++----- strings/ctype-ucs2.c | 12 +++++------- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 52dae7912af..71dc78d7593 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -276,18 +276,17 @@ void my_hash_sort_8bit_bin(CHARSET_INFO *cs __attribute__((unused)), const uchar *key, size_t len, ulong *nr1, ulong *nr2) { - const uchar *pos = key; /* Remove trailing spaces. We have to do this to be able to compare 'A ' and 'A' as identical */ - key= skip_trailing_space(key, len); + const uchar *end = skip_trailing_space(key, len); - for (; pos < (uchar*) key ; pos++) + for (; key < end ; key++) { nr1[0]^=(ulong) ((((uint) nr1[0] & 63)+nr2[0]) * - ((uint)*pos)) + (nr1[0] << 8); + ((uint)*key)) + (nr1[0] << 8); nr2[0]+=3; } } @@ -296,14 +295,12 @@ void my_hash_sort_8bit_bin(CHARSET_INFO *cs __attribute__((unused)), void my_hash_sort_bin(CHARSET_INFO *cs __attribute__((unused)), const uchar *key, size_t len,ulong *nr1, ulong *nr2) { - const uchar *pos = key; + const uchar *end = key + len; - key+= len; - - for (; pos < (uchar*) key ; pos++) + for (; key < end ; key++) { nr1[0]^=(ulong) ((((uint) nr1[0] & 63)+nr2[0]) * - ((uint)*pos)) + (nr1[0] << 8); + ((uint)*key)) + (nr1[0] << 8); nr2[0]+=3; } } diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c index c6f280dfc17..f4e70fd1dd5 100644 --- a/strings/ctype-mb.c +++ b/strings/ctype-mb.c @@ -680,18 +680,16 @@ void my_hash_sort_mb_bin(CHARSET_INFO *cs __attribute__((unused)), const uchar *key, size_t len,ulong *nr1, ulong *nr2) { - const uchar *pos = key; - /* Remove trailing spaces. We have to do this to be able to compare 'A ' and 'A' as identical */ - key= skip_trailing_space(key, len); + const uchar *end = skip_trailing_space(key, len); - for (; pos < (uchar*) key ; pos++) + for (; key < end ; key++) { nr1[0]^=(ulong) ((((uint) nr1[0] & 63)+nr2[0]) * - ((uint)*pos)) + (nr1[0] << 8); + ((uint)*key)) + (nr1[0] << 8); nr2[0]+=3; } } diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index 1a99b32c761..a7f948ebe3a 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -3311,17 +3311,15 @@ static void my_hash_sort_ucs2_bin(CHARSET_INFO *cs __attribute__((unused)), const uchar *key, size_t len,ulong *nr1, ulong *nr2) { - const uchar *pos = key; - - key+= len; + const uchar *end = key + len; - while (key > pos+1 && key[-1] == ' ' && key[-2] == '\0') - key-= 2; + while (end > key+1 && end[-1] == ' ' && end[-2] == '\0') + end-= 2; - for (; pos < (uchar*) key ; pos++) + for (; key < (uchar*) end ; key++) { nr1[0]^=(ulong) ((((uint) nr1[0] & 63)+nr2[0]) * - ((uint)*pos)) + (nr1[0] << 8); + ((uint)*key)) + (nr1[0] << 8); nr2[0]+=3; } } From 04de6ccc318ea52124399312223b8c0dc0d8fc7b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 1 Mar 2014 11:55:31 +0100 Subject: [PATCH 03/11] MDEV-5668 Assertion `granted_role->is_role()' fails on granting role with empty name parser: error out on empty role names --- .../{show_grants_anon-5238.result => grant_empty.result} | 2 ++ .../roles/{show_grants_anon-5238.test => grant_empty.test} | 6 ++++++ sql/sql_yacc.yy | 5 +++++ 3 files changed, 13 insertions(+) rename mysql-test/suite/roles/{show_grants_anon-5238.result => grant_empty.result} (77%) rename mysql-test/suite/roles/{show_grants_anon-5238.test => grant_empty.test} (70%) diff --git a/mysql-test/suite/roles/show_grants_anon-5238.result b/mysql-test/suite/roles/grant_empty.result similarity index 77% rename from mysql-test/suite/roles/show_grants_anon-5238.result rename to mysql-test/suite/roles/grant_empty.result index 85be1ac92f3..dfc0f513396 100644 --- a/mysql-test/suite/roles/show_grants_anon-5238.result +++ b/mysql-test/suite/roles/grant_empty.result @@ -1,3 +1,5 @@ +grant '' to foo@localhost; +ERROR OP000: Invalid role specification ``. create user ''@localhost; create role r1; grant r1 to ''@localhost; diff --git a/mysql-test/suite/roles/show_grants_anon-5238.test b/mysql-test/suite/roles/grant_empty.test similarity index 70% rename from mysql-test/suite/roles/show_grants_anon-5238.test rename to mysql-test/suite/roles/grant_empty.test index adb22490233..e419fffa2ba 100644 --- a/mysql-test/suite/roles/show_grants_anon-5238.test +++ b/mysql-test/suite/roles/grant_empty.test @@ -1,3 +1,9 @@ +# +# MDEV-5668 Assertion `granted_role->is_role()' fails on granting role with empty name +# +--error ER_INVALID_ROLE +grant '' to foo@localhost; + # # MDEV-5238 Server crashes in find_role_grant_pair on SHOW GRANTS for an anonymous user # diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index bcc94e80bcf..ceb4e247848 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -15192,6 +15192,11 @@ current_role: grant_role: ident_or_text { + if ($1.length == 0) + { + my_error(ER_INVALID_ROLE, MYF(0), ""); + MYSQL_YYABORT; + } if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) MYSQL_YYABORT; $$->user = $1; From 1b608b0b9c0eae7ddcd35d54a4e9112b3c1c4966 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 1 Mar 2014 13:27:04 +0100 Subject: [PATCH 04/11] MDEV-5735 Selecting from SEQUENCE table with negative number hangs server --- storage/sequence/mysql-test/sequence/simple.result | 4 ++++ storage/sequence/mysql-test/sequence/simple.test | 8 ++++++++ storage/sequence/sequence.cc | 14 ++++++++++---- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/storage/sequence/mysql-test/sequence/simple.result b/storage/sequence/mysql-test/sequence/simple.result index 2802cdeb977..8ce4722aeff 100644 --- a/storage/sequence/mysql-test/sequence/simple.result +++ b/storage/sequence/mysql-test/sequence/simple.result @@ -40,6 +40,10 @@ show create table se; ERROR 42S02: Table 'test.se' doesn't exist show create table seq_1_to_15_step_0; ERROR HY000: Got error 140 "Wrong create options" from storage engine SEQUENCE +show create table `seq_-1_to_15`; +ERROR 42S02: Table 'test.seq_-1_to_15' doesn't exist +show create table `seq_1_to_+2`; +ERROR 42S02: Table 'test.seq_1_to_+2' doesn't exist select * from seq_1_to_15_step_2; seq 1 diff --git a/storage/sequence/mysql-test/sequence/simple.test b/storage/sequence/mysql-test/sequence/simple.test index fd5b6c6d50c..fbf2b0ebc66 100644 --- a/storage/sequence/mysql-test/sequence/simple.test +++ b/storage/sequence/mysql-test/sequence/simple.test @@ -26,6 +26,14 @@ show create table se; --error ER_GET_ERRNO show create table seq_1_to_15_step_0; +# +# MDEV-5735 Selecting from SEQUENCE table with negative number hangs server +# +--error ER_NO_SUCH_TABLE +show create table `seq_-1_to_15`; +--error ER_NO_SUCH_TABLE +show create table `seq_1_to_+2`; + # simple select select * from seq_1_to_15_step_2; select * from seq_1_to_15; diff --git a/storage/sequence/sequence.cc b/storage/sequence/sequence.cc index ab22037d884..0d92c324724 100644 --- a/storage/sequence/sequence.cc +++ b/storage/sequence/sequence.cc @@ -20,6 +20,7 @@ a engine that auto-creates tables with rows filled with sequential values */ +#include #include #include #include @@ -265,14 +266,19 @@ static handler *create_handler(handlerton *hton, TABLE_SHARE *table, static bool parse_table_name(const char *name, size_t name_length, ulonglong *from, ulonglong *to, ulonglong *step) { - uint n1= 0, n2= 0; + uint n0=0, n1= 0, n2= 0; *step= 1; // the table is discovered if its name matches the pattern of seq_1_to_10 or // seq_1_to_10_step_3 - sscanf(name, "seq_%llu_to_%llu%n_step_%llu%n", - from, to, &n1, step, &n2); - return n1 != name_length && n2 != name_length; + sscanf(name, "seq_%llu_to_%n%llu%n_step_%llu%n", + from, &n0, to, &n1, step, &n2); + // I consider this a bug in sscanf() - when an unsigned number + // is requested, -5 should *not* be accepted. But is is :( + // hence the additional check below: + return + n0 == 0 || !isdigit(name[4]) || !isdigit(name[n0]) || // reject negative numbers + (n1 != name_length && n2 != name_length); } From eb9f422c43406172422eeaaa29dddeff742b6d14 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 2 Mar 2014 15:02:13 +0100 Subject: [PATCH 05/11] MDEV-5667 online alter and changed field/index options use the Alter_inplace_info::ALTER_COLUMN_OPTION flag if field/column flags were altered. change ha_example to use check_if_supported_inplace_alter() instead of obsolete check_if_incompatible_data() --- mysql-test/r/plugin.result | 18 ++--- mysql-test/t/plugin.test | 2 +- sql/handler.cc | 1 + sql/handler.h | 9 ++- sql/sql_table.cc | 12 +++- storage/example/ha_example.cc | 128 +++++++++++++++++----------------- storage/example/ha_example.h | 5 +- 7 files changed, 93 insertions(+), 82 deletions(-) diff --git a/mysql-test/r/plugin.result b/mysql-test/r/plugin.result index d304f094987..54693eaee56 100644 --- a/mysql-test/r/plugin.result +++ b/mysql-test/r/plugin.result @@ -127,7 +127,7 @@ drop table t1; SET @OLD_SQL_MODE=@@SQL_MODE; SET SQL_MODE='IGNORE_BAD_TABLE_OPTIONS'; #illegal value fixed -CREATE TABLE t1 (a int) ENGINE=example ULL=10000000000000000000 one_or_two='ttt' YESNO=SSS; +CREATE TABLE t1 (a int, b int) ENGINE=example ULL=10000000000000000000 one_or_two='ttt' YESNO=SSS; Warnings: Warning 1912 Incorrect value '10000000000000000000' for option 'ULL' Warning 1912 Incorrect value 'ttt' for option 'one_or_two' @@ -135,7 +135,8 @@ Warning 1912 Incorrect value 'SSS' for option 'YESNO' show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` int(11) DEFAULT NULL + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL ) ENGINE=EXAMPLE DEFAULT CHARSET=latin1 `ULL`=10000000000000000000 `one_or_two`='ttt' `YESNO`=SSS `VAROPT`='5' #alter table alter table t1 ULL=10000000; @@ -144,7 +145,8 @@ Note 1105 EXAMPLE DEBUG: ULL 4294967290 -> 10000000 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` int(11) DEFAULT NULL + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL ) ENGINE=EXAMPLE DEFAULT CHARSET=latin1 `one_or_two`='ttt' `YESNO`=SSS `VAROPT`='5' `ULL`=10000000 alter table t1 change a a int complex='c,c,c'; Warnings: @@ -152,15 +154,15 @@ Note 1105 EXAMPLE DEBUG: Field `a` COMPLEX '(null)' -> 'c,c,c' show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` int(11) DEFAULT NULL `complex`='c,c,c' + `a` int(11) DEFAULT NULL `complex`='c,c,c', + `b` int(11) DEFAULT NULL ) ENGINE=EXAMPLE DEFAULT CHARSET=latin1 `one_or_two`='ttt' `YESNO`=SSS `VAROPT`='5' `ULL`=10000000 alter table t1 one_or_two=two; -Warnings: -Note 1105 EXAMPLE DEBUG: Field `a` COMPLEX 'c,c,c' -> 'c,c,c' show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` int(11) DEFAULT NULL `complex`='c,c,c' + `a` int(11) DEFAULT NULL `complex`='c,c,c', + `b` int(11) DEFAULT NULL ) ENGINE=EXAMPLE DEFAULT CHARSET=latin1 `YESNO`=SSS `VAROPT`='5' `ULL`=10000000 `one_or_two`=two drop table t1; #illegal value error @@ -204,8 +206,6 @@ t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=EXAMPLE DEFAULT CHARSET=latin1 `varopt`=15 alter table t1 varopt=default; -Warnings: -Note 1105 EXAMPLE DEBUG: Field `a` COMPLEX '(null)' -> '(null)' show create table t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/mysql-test/t/plugin.test b/mysql-test/t/plugin.test index eda70dafc30..fb608ee5bf8 100644 --- a/mysql-test/t/plugin.test +++ b/mysql-test/t/plugin.test @@ -121,7 +121,7 @@ SET @OLD_SQL_MODE=@@SQL_MODE; SET SQL_MODE='IGNORE_BAD_TABLE_OPTIONS'; --echo #illegal value fixed -CREATE TABLE t1 (a int) ENGINE=example ULL=10000000000000000000 one_or_two='ttt' YESNO=SSS; +CREATE TABLE t1 (a int, b int) ENGINE=example ULL=10000000000000000000 one_or_two='ttt' YESNO=SSS; show create table t1; --echo #alter table diff --git a/sql/handler.cc b/sql/handler.cc index 8aee24fbe03..50044cf3cab 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -4123,6 +4123,7 @@ handler::check_if_supported_inplace_alter(TABLE *altered_table, Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH | Alter_inplace_info::ALTER_COLUMN_NAME | Alter_inplace_info::ALTER_COLUMN_DEFAULT | + Alter_inplace_info::ALTER_COLUMN_OPTION | Alter_inplace_info::CHANGE_CREATE_OPTION | Alter_inplace_info::ALTER_RENAME; diff --git a/sql/handler.h b/sql/handler.h index d255c0543a9..06bc1863bbe 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1740,8 +1740,11 @@ public: // Table is renamed static const HA_ALTER_FLAGS ALTER_RENAME = 1L << 18; - // Change the storage type of column - static const HA_ALTER_FLAGS ALTER_COLUMN_STORAGE_TYPE = 1L << 19; + // column's engine options changed, something in field->option_struct + static const HA_ALTER_FLAGS ALTER_COLUMN_OPTION = 1L << 19; + + // MySQL alias for the same thing: + static const HA_ALTER_FLAGS ALTER_COLUMN_STORAGE_TYPE = 1L << 19; // Change the column format of column static const HA_ALTER_FLAGS ALTER_COLUMN_COLUMN_FORMAT = 1L << 20; @@ -1770,7 +1773,7 @@ public: // Partition operation with ALL keyword static const HA_ALTER_FLAGS ALTER_ALL_PARTITION = 1L << 28; - // Partition operation with ALL keyword + // Virtual columns changed static const HA_ALTER_FLAGS ALTER_COLUMN_VCOL = 1L << 29; /** diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c43ea8c453c..fdb902ee199 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5894,9 +5894,6 @@ static bool fill_alter_inplace_info(THD *thd, if (new_field) { - ha_alter_info->create_info->fields_option_struct[f_ptr - table->field]= - new_field->option_struct; - /* Field is not dropped. Evaluate changes bitmap for it. */ /* @@ -6008,6 +6005,15 @@ static bool fill_alter_inplace_info(THD *thd, if (new_field->column_format() != field->column_format()) ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_COLUMN_FORMAT; + + if (engine_options_differ(field->option_struct, new_field->option_struct, + table->file->ht->field_options)) + { + ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_OPTION; + ha_alter_info->create_info->fields_option_struct[f_ptr - table->field]= + new_field->option_struct; + } + } else { diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc index f31bffb361a..930c4f38633 100644 --- a/storage/example/ha_example.cc +++ b/storage/example/ha_example.cc @@ -906,84 +906,84 @@ int ha_example::create(const char *name, TABLE *table_arg, /** - check_if_incompatible_data() called if ALTER TABLE can't detect otherwise - if new and old definition are compatible + check_if_supported_inplace_alter() is used to ask the engine whether + it can execute this ALTER TABLE statement in place or the server needs to + create a new table and copy th data over. - @details If there are no other explicit signs like changed number of - fields this function will be called by compare_tables() - (sql/sql_tables.cc) to decide should we rewrite whole table or only .frm - file. + The engine may answer that the inplace alter is not supported or, + if supported, whether the server should protect the table from concurrent + accesses. Return values are + HA_ALTER_INPLACE_NOT_SUPPORTED + HA_ALTER_INPLACE_EXCLUSIVE_LOCK + HA_ALTER_INPLACE_SHARED_LOCK + etc */ -bool ha_example::check_if_incompatible_data(HA_CREATE_INFO *info, - uint table_changes) +enum_alter_inplace_result +ha_example::check_if_supported_inplace_alter(TABLE* altered_table, + Alter_inplace_info* ha_alter_info) { - ha_table_option_struct *param_old, *param_new; - DBUG_ENTER("ha_example::check_if_incompatible_data"); - /* - This example shows how custom engine specific table and field - options can be accessed from this function to be compared. - */ - param_new= info->option_struct; - DBUG_PRINT("info", ("new strparam: '%-.64s' ullparam: %llu enumparam: %u " - "boolparam: %u", - (param_new->strparam ? param_new->strparam : ""), - param_new->ullparam, param_new->enumparam, - param_new->boolparam)); + HA_CREATE_INFO *info= ha_alter_info->create_info; + DBUG_ENTER("ha_example::check_if_supported_inplace_alter"); - param_old= table->s->option_struct; - DBUG_PRINT("info", ("old strparam: '%-.64s' ullparam: %llu enumparam: %u " - "boolparam: %u", - (param_old->strparam ? param_old->strparam : ""), - param_old->ullparam, param_old->enumparam, - param_old->boolparam)); - - /* - check important parameters: - for this example engine, we'll assume that changing ullparam or - boolparam requires a table to be rebuilt, while changing strparam - or enumparam - does not. - - For debugging purposes we'll announce this to the user - (don't do it in production!) - - */ - if (param_new->ullparam != param_old->ullparam) + if (ha_alter_info->handler_flags & Alter_inplace_info::CHANGE_CREATE_OPTION) { - push_warning_printf(ha_thd(), Sql_condition::WARN_LEVEL_NOTE, - ER_UNKNOWN_ERROR, "EXAMPLE DEBUG: ULL %llu -> %llu", - param_old->ullparam, param_new->ullparam); - DBUG_RETURN(COMPATIBLE_DATA_NO); - } + /* + This example shows how custom engine specific table and field + options can be accessed from this function to be compared. + */ + ha_table_option_struct *param_new= info->option_struct; + ha_table_option_struct *param_old= table->s->option_struct; - if (param_new->boolparam != param_old->boolparam) - { - push_warning_printf(ha_thd(), Sql_condition::WARN_LEVEL_NOTE, - ER_UNKNOWN_ERROR, "EXAMPLE DEBUG: YESNO %u -> %u", - param_old->boolparam, param_new->boolparam); - DBUG_RETURN(COMPATIBLE_DATA_NO); - } + /* + check important parameters: + for this example engine, we'll assume that changing ullparam or + boolparam requires a table to be rebuilt, while changing strparam + or enumparam - does not. - for (uint i= 0; i < table->s->fields; i++) - { - ha_field_option_struct *f_old, *f_new; - f_old= table->s->field[i]->option_struct; - DBUG_ASSERT(f_old); - if (info->fields_option_struct[i]) + For debugging purposes we'll announce this to the user + (don't do it in production!) + + */ + if (param_new->ullparam != param_old->ullparam) { - f_new= info->fields_option_struct[i]; push_warning_printf(ha_thd(), Sql_condition::WARN_LEVEL_NOTE, - ER_UNKNOWN_ERROR, "EXAMPLE DEBUG: Field %`s COMPLEX '%s' -> '%s'", - table->s->field[i]->field_name, - f_old->complex_param_to_parse_it_in_engine, - f_new->complex_param_to_parse_it_in_engine); + ER_UNKNOWN_ERROR, "EXAMPLE DEBUG: ULL %llu -> %llu", + param_old->ullparam, param_new->ullparam); + DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); + } + + if (param_new->boolparam != param_old->boolparam) + { + push_warning_printf(ha_thd(), Sql_condition::WARN_LEVEL_NOTE, + ER_UNKNOWN_ERROR, "EXAMPLE DEBUG: YESNO %u -> %u", + param_old->boolparam, param_new->boolparam); + DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } - else - DBUG_PRINT("info", ("old field %i did not changed", i)); } - DBUG_RETURN(COMPATIBLE_DATA_YES); + if (ha_alter_info->handler_flags & Alter_inplace_info::ALTER_COLUMN_OPTION) + { + for (uint i= 0; i < table->s->fields; i++) + { + ha_field_option_struct *f_old= table->s->field[i]->option_struct; + ha_field_option_struct *f_new= info->fields_option_struct[i]; + DBUG_ASSERT(f_old); + if (f_new) + { + push_warning_printf(ha_thd(), Sql_condition::WARN_LEVEL_NOTE, + ER_UNKNOWN_ERROR, "EXAMPLE DEBUG: Field %`s COMPLEX '%s' -> '%s'", + table->s->field[i]->field_name, + f_old->complex_param_to_parse_it_in_engine, + f_new->complex_param_to_parse_it_in_engine); + } + else + DBUG_PRINT("info", ("old field %i did not changed", i)); + } + } + + DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK); } diff --git a/storage/example/ha_example.h b/storage/example/ha_example.h index d25541f7422..2d3d0c81ed9 100644 --- a/storage/example/ha_example.h +++ b/storage/example/ha_example.h @@ -247,8 +247,9 @@ public: int delete_table(const char *from); int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); ///< required - bool check_if_incompatible_data(HA_CREATE_INFO *info, - uint table_changes); + enum_alter_inplace_result + check_if_supported_inplace_alter(TABLE* altered_table, + Alter_inplace_info* ha_alter_info); THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type); ///< required From 66883ee08d6ea4f96cb4473181508b511ece39f5 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 2 Mar 2014 15:54:57 +0100 Subject: [PATCH 06/11] MDEV-5674 Valgrind warnings "Conditional jump or move depends on uninitialised value" in create_sort_index with small sort_buffer_size *found_rows wasn't initialized when filesort() failed (it didn't matter, but valgrind was unhappy) --- sql/filesort.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/filesort.cc b/sql/filesort.cc index 9f178938f24..12b9bb5aadc 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -188,6 +188,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, my_b_clear(&buffpek_pointers); buffpek=0; error= 1; + *found_rows= HA_POS_ERROR; param.init_for_filesort(sortlength(thd, sortorder, s_length, &multi_byte_charset), From 8705d00ab62b4d3f749b4b8cba07718e8fd54bcb Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 2 Mar 2014 19:01:34 +0100 Subject: [PATCH 07/11] MDEV-5748 Assertion `status_var.memory_used == 0' fails on disconnect after opening an OQGRAPH table make sure MY_THREAD_SPECIFIC is not set for memroot that can be transferred between threads --- storage/oqgraph/ha_oqgraph.cc | 4 ++ .../oqgraph/connections_mdev5748.result | 32 ++++++++++++++++ .../oqgraph/connections_mdev5748.test | 37 +++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 storage/oqgraph/mysql-test/oqgraph/connections_mdev5748.result create mode 100644 storage/oqgraph/mysql-test/oqgraph/connections_mdev5748.test diff --git a/storage/oqgraph/ha_oqgraph.cc b/storage/oqgraph/ha_oqgraph.cc index 12a39e0f230..650be75ceda 100644 --- a/storage/oqgraph/ha_oqgraph.cc +++ b/storage/oqgraph/ha_oqgraph.cc @@ -538,7 +538,11 @@ int ha_oqgraph::open(const char *name, int mode, uint test_if_locked) origid= destid= weight= 0; + // Here we're abusing init_tmp_table_share() which is normally only works for thread-local shares. init_tmp_table_share( thd, share, table->s->db.str, table->s->db.length, options->table_name, ""); + // because of that, we need to reinitialize the memroot (to reset MY_THREAD_SPECIFIC flag) + DBUG_ASSERT(share->mem_root.used == NULL); // it's still empty + init_sql_alloc(&share->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0)); // What I think this code is doing: // * Our OQGRAPH table is `database_blah/name` diff --git a/storage/oqgraph/mysql-test/oqgraph/connections_mdev5748.result b/storage/oqgraph/mysql-test/oqgraph/connections_mdev5748.result new file mode 100644 index 00000000000..3d9c13bd733 --- /dev/null +++ b/storage/oqgraph/mysql-test/oqgraph/connections_mdev5748.result @@ -0,0 +1,32 @@ +CREATE TABLE oq_backing ( +origid INT UNSIGNED NOT NULL, +destid INT UNSIGNED NOT NULL, +weight DOUBLE NOT NULL, +PRIMARY KEY (origid, destid), +KEY (destid) +); +CREATE TABLE oq_table ( +latch VARCHAR(32) NULL, +origid BIGINT UNSIGNED NULL, +destid BIGINT UNSIGNED NULL, +weight DOUBLE NULL, +seq BIGINT UNSIGNED NULL, +linkid BIGINT UNSIGNED NULL, +KEY (latch, origid, destid) USING HASH, +KEY (latch, destid, origid) USING HASH +) ENGINE=OQGRAPH +data_table='oq_backing' origid='origid' destid='destid' weight='weight'; +flush tables; +show fields in oq_table; +Field Type Null Key Default Extra +latch varchar(32) YES MUL NULL +origid bigint(20) unsigned YES NULL +destid bigint(20) unsigned YES NULL +weight double YES NULL +seq bigint(20) unsigned YES NULL +linkid bigint(20) unsigned YES NULL +show tables; +Tables_in_test +oq_backing +oq_table +drop table oq_table, oq_backing; diff --git a/storage/oqgraph/mysql-test/oqgraph/connections_mdev5748.test b/storage/oqgraph/mysql-test/oqgraph/connections_mdev5748.test new file mode 100644 index 00000000000..9d7fab722c0 --- /dev/null +++ b/storage/oqgraph/mysql-test/oqgraph/connections_mdev5748.test @@ -0,0 +1,37 @@ +# +# MDEV-5748 Assertion `status_var.memory_used == 0' fails on disconnect after opening an OQGRAPH table +# + +# try to open oqgraph table in one connection and use in another: + +--connect (con1,localhost,root,,) + +CREATE TABLE oq_backing ( + origid INT UNSIGNED NOT NULL, + destid INT UNSIGNED NOT NULL, + weight DOUBLE NOT NULL, + PRIMARY KEY (origid, destid), + KEY (destid) +); + +CREATE TABLE oq_table ( + latch VARCHAR(32) NULL, + origid BIGINT UNSIGNED NULL, + destid BIGINT UNSIGNED NULL, + weight DOUBLE NULL, + seq BIGINT UNSIGNED NULL, + linkid BIGINT UNSIGNED NULL, + KEY (latch, origid, destid) USING HASH, + KEY (latch, destid, origid) USING HASH +) ENGINE=OQGRAPH +data_table='oq_backing' origid='origid' destid='destid' weight='weight'; + +flush tables; +show fields in oq_table; +--disconnect con1 + +--connection default +show tables; + +drop table oq_table, oq_backing; + From 641feed481800d9baadc492a293723da274d8ed6 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 3 Mar 2014 12:13:55 +0100 Subject: [PATCH 08/11] MDEV-5764: START SLAVE UNTIL does not work with parallel replication With parallel replication, there can be any number of events queued on in-memory lists in the worker threads. For normal STOP SLAVE, we want to skip executing any remaining events on those lists and stop as quickly as possible. However, for START SLAVE UNTIL, when the UNTIL position is reached in the SQL driver thread, we must _not_ stop until all already queued events for the workers have been executed - otherwise we would stop too early, before the actual UNTIL position had been completely reached. The code did not handle UNTIL correctly, stopping too early due to not executing the queued events to completion. Fix this, and also implement that an explicit STOP SLAVE in the middle (when the SQL driver thread has reached the UNTIL position but the workers have not) _will_ cause an immediate stop. --- sql/log_event.cc | 7 ++++--- sql/rpl_parallel.cc | 33 +++++++++++++++++++++++++++++++-- sql/rpl_parallel.h | 3 ++- sql/rpl_rli.cc | 3 ++- sql/rpl_rli.h | 1 + sql/slave.cc | 15 ++++++++++++--- 6 files changed, 52 insertions(+), 10 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index d0cfa799d3c..361efe4428e 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6649,7 +6649,7 @@ Gtid_list_log_event::write(IO_CACHE *file) int Gtid_list_log_event::do_apply_event(rpl_group_info *rgi) { - Relay_log_info const *rli= rgi->rli; + Relay_log_info *rli= const_cast(rgi->rli); int ret; if (gl_flags & FLAG_IGN_GTIDS) { @@ -6669,10 +6669,11 @@ Gtid_list_log_event::do_apply_event(rpl_group_info *rgi) { char str_buf[128]; String str(str_buf, sizeof(str_buf), system_charset_info); - const_cast(rli)->until_gtid_pos.to_string(&str); + rli->until_gtid_pos.to_string(&str); sql_print_information("Slave SQL thread stops because it reached its" " UNTIL master_gtid_pos %s", str.c_ptr_safe()); - const_cast(rli)->abort_slave= true; + rli->abort_slave= true; + rli->stop_for_until= true; } return ret; } diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index eab5b980c02..cceb6013d6c 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -173,6 +173,7 @@ signal_error_to_sql_driver_thread(THD *thd, rpl_group_info *rgi) rgi->is_error= true; rgi->cleanup_context(thd, true); rgi->rli->abort_slave= true; + rgi->rli->stop_for_until= false; mysql_mutex_lock(rgi->rli->relay_log.get_log_lock()); mysql_mutex_unlock(rgi->rli->relay_log.get_log_lock()); rgi->rli->relay_log.signal_update(); @@ -1122,7 +1123,7 @@ rpl_parallel::find(uint32 domain_id) void -rpl_parallel::wait_for_done(THD *thd) +rpl_parallel::wait_for_done(THD *thd, Relay_log_info *rli) { struct rpl_parallel_entry *e; rpl_parallel_thread *rpt; @@ -1152,9 +1153,13 @@ rpl_parallel::wait_for_done(THD *thd) started executing yet. So we set e->stop_count here and use it to decide in the worker threads whether to continue executing an event group or whether to skip it, when force_abort is set. + + If we stop due to reaching the START SLAVE UNTIL condition, then we + need to continue executing any queued events up to that point. */ e->force_abort= true; - e->stop_count= e->count_committing_event_groups; + e->stop_count= rli->stop_for_until ? + e->count_queued_event_groups : e->count_committing_event_groups; mysql_mutex_unlock(&e->LOCK_parallel_entry); for (j= 0; j < e->rpl_thread_max; ++j) { @@ -1190,6 +1195,30 @@ rpl_parallel::wait_for_done(THD *thd) } +/* + This function handles the case where the SQL driver thread reached the + START SLAVE UNTIL position; we stop queueing more events but continue + processing remaining, already queued events; then use executes manual + STOP SLAVE; then this function signals to worker threads that they + should stop the processing of any remaining queued events. +*/ +void +rpl_parallel::stop_during_until() +{ + struct rpl_parallel_entry *e; + uint32 i; + + for (i= 0; i < domain_hash.records; ++i) + { + e= (struct rpl_parallel_entry *)my_hash_element(&domain_hash, i); + mysql_mutex_lock(&e->LOCK_parallel_entry); + if (e->force_abort) + e->stop_count= e->count_committing_event_groups; + mysql_mutex_unlock(&e->LOCK_parallel_entry); + } +} + + bool rpl_parallel::workers_idle() { diff --git a/sql/rpl_parallel.h b/sql/rpl_parallel.h index 90649230f98..31a6a035dd8 100644 --- a/sql/rpl_parallel.h +++ b/sql/rpl_parallel.h @@ -222,7 +222,8 @@ struct rpl_parallel { ~rpl_parallel(); void reset(); rpl_parallel_entry *find(uint32 domain_id); - void wait_for_done(THD *thd); + void wait_for_done(THD *thd, Relay_log_info *rli); + void stop_during_until(); bool workers_idle(); bool do_event(rpl_group_info *serial_rgi, Log_event *ev, ulonglong event_size); diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index ffe5e516069..26776bb46f3 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -60,7 +60,8 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery) group_master_log_pos(0), log_space_total(0), ignore_log_space_limit(0), last_master_timestamp(0), sql_thread_caught_up(true), slave_skip_counter(0), abort_pos_wait(0), slave_run_id(0), sql_driver_thd(), - inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE), + inited(0), abort_slave(0), stop_for_until(0), + slave_running(0), until_condition(UNTIL_NONE), until_log_pos(0), retried_trans(0), executed_entries(0), m_flags(0) { diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 0ba259b0efd..6db4ce5d61b 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -262,6 +262,7 @@ public: */ volatile bool inited; volatile bool abort_slave; + volatile bool stop_for_until; volatile uint slave_running; /* diff --git a/sql/slave.cc b/sql/slave.cc index b081a3369f5..29515fb3821 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -615,7 +615,14 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock) if (thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL)) { DBUG_PRINT("info",("Terminating SQL thread")); - mi->rli.abort_slave=1; + if (opt_slave_parallel_threads > 0 && + mi->rli.abort_slave && mi->rli.stop_for_until) + { + mi->rli.stop_for_until= false; + mi->rli.parallel.stop_during_until(); + } + else + mi->rli.abort_slave=1; if ((error=terminate_slave_thread(mi->rli.sql_driver_thd, sql_lock, &mi->rli.stop_cond, &mi->rli.slave_running, @@ -3414,6 +3421,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli, message about error in query execution to be printed. */ rli->abort_slave= 1; + rli->stop_for_until= true; mysql_mutex_unlock(&rli->data_lock); delete ev; DBUG_RETURN(1); @@ -4356,6 +4364,7 @@ pthread_handler_t handle_slave_sql(void *arg) Seconds_Behind_Master grows. No big deal. */ rli->abort_slave = 0; + rli->stop_for_until= false; mysql_mutex_unlock(&rli->run_lock); mysql_cond_broadcast(&rli->start_cond); @@ -4526,7 +4535,7 @@ log '%s' at position %s, relay log '%s' position: %s%s", RPL_LOG_NAME, } if (opt_slave_parallel_threads > 0) - rli->parallel.wait_for_done(thd); + rli->parallel.wait_for_done(thd, rli); /* Thread stopped. Print the current replication position to the log */ { @@ -4552,7 +4561,7 @@ log '%s' at position %s, relay log '%s' position: %s%s", RPL_LOG_NAME, get the correct position printed.) */ if (opt_slave_parallel_threads > 0) - rli->parallel.wait_for_done(thd); + rli->parallel.wait_for_done(thd, rli); /* Some events set some playgrounds, which won't be cleared because thread From 016bd4fc5fff311dc4091b3b7329cd980dbaa14b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 4 Mar 2014 01:22:53 +0100 Subject: [PATCH 09/11] MDEV-5620 CMake option to compile against an external PCRE library --- CMakeLists.txt | 4 +++- client/CMakeLists.txt | 3 +-- cmake/jemalloc.cmake | 2 +- cmake/pcre.cmake | 16 ++++++++++++++++ cmake/plugin.cmake | 3 +-- libmysql/CMakeLists.txt | 3 +-- libmysqld/CMakeLists.txt | 3 +-- libmysqld/examples/CMakeLists.txt | 3 +-- plugin/feedback/CMakeLists.txt | 3 +-- plugin/qc_info/CMakeLists.txt | 3 +-- sql/CMakeLists.txt | 3 +-- storage/perfschema/CMakeLists.txt | 3 +-- storage/perfschema/unittest/CMakeLists.txt | 3 +-- unittest/mysys/CMakeLists.txt | 3 +-- 14 files changed, 31 insertions(+), 24 deletions(-) create mode 100644 cmake/pcre.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 4859bb89e0b..f8ebddc70fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,7 @@ INCLUDE(readline) INCLUDE(libutils) INCLUDE(dtrace) INCLUDE(jemalloc) +INCLUDE(pcre) INCLUDE(ctest) INCLUDE(plugin) INCLUDE(install_macros) @@ -362,6 +363,8 @@ MYSQL_CHECK_READLINE() SET(MALLOC_LIBRARY "system") CHECK_JEMALLOC() +CHECK_PCRE() + # # Setup maintainer mode options. Platform checks are # not run with the warning options as to not perturb fragile checks @@ -397,7 +400,6 @@ ADD_SUBDIRECTORY(include) ADD_SUBDIRECTORY(dbug) ADD_SUBDIRECTORY(strings) ADD_SUBDIRECTORY(vio) -ADD_SUBDIRECTORY(pcre) ADD_SUBDIRECTORY(mysys) ADD_SUBDIRECTORY(mysys_ssl) ADD_SUBDIRECTORY(libmysql) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 7f725e09006..1bf466c1e47 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -15,8 +15,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/include - ${CMAKE_BINARY_DIR}/pcre - ${CMAKE_SOURCE_DIR}/pcre + ${PCRE_INCLUDES} ${CMAKE_SOURCE_DIR}/mysys_ssl ${ZLIB_INCLUDE_DIR} ${SSL_INCLUDE_DIRS} diff --git a/cmake/jemalloc.cmake b/cmake/jemalloc.cmake index 3df17f362bc..b677f226266 100644 --- a/cmake/jemalloc.cmake +++ b/cmake/jemalloc.cmake @@ -46,7 +46,7 @@ ELSE() ENDIF() SET(WITH_JEMALLOC ${WITH_JEMALLOC_DEFAULT} CACHE STRING - "Which jemalloc to use (possible values are 'no', 'bundled', 'system', 'yes' (system if possible, otherwise bundled)") + "Which jemalloc to use. Possible values are 'no', 'bundled', 'system', 'yes' (system if possible, otherwise bundled)") MACRO (CHECK_JEMALLOC) IF(WITH_JEMALLOC STREQUAL "system" OR WITH_JEMALLOC STREQUAL "yes") diff --git a/cmake/pcre.cmake b/cmake/pcre.cmake new file mode 100644 index 00000000000..45d9bc01ddb --- /dev/null +++ b/cmake/pcre.cmake @@ -0,0 +1,16 @@ +SET(WITH_PCRE "auto" CACHE STRING + "Which pcre to use (possible values are 'bundled', 'system', or 'auto')") + +MACRO (CHECK_PCRE) + IF(WITH_PCRE STREQUAL "system" OR WITH_PCRE STREQUAL "auto") + CHECK_LIBRARY_EXISTS(pcre pcre_stack_guard "" HAVE_PCRE) + ENDIF() + IF(NOT HAVE_PCRE) + IF (WITH_PCRE STREQUAL "system") + MESSAGE(FATAL_ERROR "system pcre is not found or unusable") + ENDIF() + SET(PCRE_INCLUDES ${CMAKE_BINARY_DIR}/pcre ${CMAKE_SOURCE_DIR}/pcre) + ADD_SUBDIRECTORY(pcre) + ENDIF() +ENDMACRO() + diff --git a/cmake/plugin.cmake b/cmake/plugin.cmake index d0847f1f84e..07372849a10 100644 --- a/cmake/plugin.cmake +++ b/cmake/plugin.cmake @@ -37,8 +37,7 @@ MACRO(MYSQL_ADD_PLUGIN) # Add common include directories INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql - ${CMAKE_BINARY_DIR}/pcre - ${CMAKE_SOURCE_DIR}/pcre + ${PCRE_INCLUDES} ${SSL_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR}) diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt index 3a6cb9d0788..e3c932c88f0 100644 --- a/libmysql/CMakeLists.txt +++ b/libmysql/CMakeLists.txt @@ -17,8 +17,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/libmysql - ${CMAKE_BINARY_DIR}/pcre - ${CMAKE_SOURCE_DIR}/pcre + ${PCRE_INCLUDES} ${CMAKE_SOURCE_DIR}/strings ${SSL_INCLUDE_DIRS} ${SSL_INTERNAL_INCLUDE_DIRS} diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 3bcaab597b7..d0c3fafdf69 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -22,8 +22,7 @@ ${CMAKE_SOURCE_DIR}/libmysql ${CMAKE_SOURCE_DIR}/libmysqld ${CMAKE_SOURCE_DIR}/sql ${CMAKE_BINARY_DIR}/sql -${CMAKE_BINARY_DIR}/pcre -${CMAKE_SOURCE_DIR}/pcre +${PCRE_INCLUDES} ${ZLIB_INCLUDE_DIR} ${SSL_INCLUDE_DIRS} ${SSL_INTERNAL_INCLUDE_DIRS} diff --git a/libmysqld/examples/CMakeLists.txt b/libmysqld/examples/CMakeLists.txt index cf23fdc4a6a..d47638ad2f9 100644 --- a/libmysqld/examples/CMakeLists.txt +++ b/libmysqld/examples/CMakeLists.txt @@ -15,8 +15,7 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/libmysqld/include - ${CMAKE_BINARY_DIR}/pcre - ${CMAKE_SOURCE_DIR}/pcre + ${PCRE_INCLUDES} ${CMAKE_SOURCE_DIR}/sql ${MY_READLINE_INCLUDE_DIR} ) diff --git a/plugin/feedback/CMakeLists.txt b/plugin/feedback/CMakeLists.txt index 919324fb63b..9807eadbe34 100644 --- a/plugin/feedback/CMakeLists.txt +++ b/plugin/feedback/CMakeLists.txt @@ -1,6 +1,5 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql - ${CMAKE_BINARY_DIR}/pcre - ${CMAKE_SOURCE_DIR}/pcre + ${PCRE_INCLUDES} ${SSL_INCLUDE_DIRS}) SET(FEEDBACK_SOURCES feedback.cc sender_thread.cc diff --git a/plugin/qc_info/CMakeLists.txt b/plugin/qc_info/CMakeLists.txt index ca59130b072..d10f4547227 100644 --- a/plugin/qc_info/CMakeLists.txt +++ b/plugin/qc_info/CMakeLists.txt @@ -1,6 +1,5 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql - ${CMAKE_BINARY_DIR}/pcre - ${CMAKE_SOURCE_DIR}/pcre + ${PCRE_INCLUDES} ${CMAKE_SOURCE_DIR}/extra/yassl/include) MYSQL_ADD_PLUGIN(QUERY_CACHE_INFO qc_info.cc) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 187a4e9de5e..ad4b12813d3 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -16,8 +16,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql -${CMAKE_BINARY_DIR}/pcre -${CMAKE_SOURCE_DIR}/pcre +${PCRE_INCLUDES} ${ZLIB_INCLUDE_DIR} ${SSL_INCLUDE_DIRS} ${CMAKE_BINARY_DIR}/sql diff --git a/storage/perfschema/CMakeLists.txt b/storage/perfschema/CMakeLists.txt index 422d29464ae..718baa8296b 100644 --- a/storage/perfschema/CMakeLists.txt +++ b/storage/perfschema/CMakeLists.txt @@ -16,8 +16,7 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql - ${CMAKE_BINARY_DIR}/pcre - ${CMAKE_SOURCE_DIR}/pcre + ${PCRE_INCLUDES} ${CMAKE_SOURCE_DIR}/extra/yassl/include) ADD_DEFINITIONS(-DMYSQL_SERVER) diff --git a/storage/perfschema/unittest/CMakeLists.txt b/storage/perfschema/unittest/CMakeLists.txt index d42d448d1e9..b44d0173029 100644 --- a/storage/perfschema/unittest/CMakeLists.txt +++ b/storage/perfschema/unittest/CMakeLists.txt @@ -15,8 +15,7 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include/mysql - ${CMAKE_BINARY_DIR}/pcre - ${CMAKE_SOURCE_DIR}/pcre + ${PCRE_INCLUDES} ${CMAKE_SOURCE_DIR}/sql ${SSL_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/unittest/mytap diff --git a/unittest/mysys/CMakeLists.txt b/unittest/mysys/CMakeLists.txt index 6ea764070f1..a6003b7c51d 100644 --- a/unittest/mysys/CMakeLists.txt +++ b/unittest/mysys/CMakeLists.txt @@ -14,8 +14,7 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql - ${CMAKE_BINARY_DIR}/pcre - ${CMAKE_SOURCE_DIR}/pcre + ${PCRE_INCLUDES} ${CMAKE_SOURCE_DIR}/extra/yassl/include) MY_ADD_TESTS(bitmap base64 my_vsnprintf my_atomic my_rdtsc lf my_malloc From ec374f1e53fc384bca65f9ab51dd5e0f4af20a1e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 4 Mar 2014 08:48:32 +0100 Subject: [PATCH 10/11] MDEV-5769: Slave crashes on attempt to do parallel replication from an older master Older master has no GTID events, so such events are not available for deciding on scheduling of event groups and so on. With this patch, we run such events from old masters single-threaded, in the sql driver thread. This seems better than trying to make the parallel code handle the data from older masters; while possible, this would require a lot of testing (as well as possibly some extra overhead in the scheduling of events), which hardly seems worthwhile. --- mysql-test/std_data/mariadb-5.5-binlog.000001 | Bin 0 -> 1037 bytes mysql-test/suite/rpl/r/rpl_old_master.result | 27 ++++++ mysql-test/suite/rpl/t/rpl_old_master.test | 49 +++++++++++ sql/rpl_parallel.cc | 82 ++++++++++-------- sql/rpl_parallel.h | 3 +- sql/slave.cc | 18 ++-- 6 files changed, 134 insertions(+), 45 deletions(-) create mode 100644 mysql-test/std_data/mariadb-5.5-binlog.000001 create mode 100644 mysql-test/suite/rpl/r/rpl_old_master.result create mode 100644 mysql-test/suite/rpl/t/rpl_old_master.test diff --git a/mysql-test/std_data/mariadb-5.5-binlog.000001 b/mysql-test/std_data/mariadb-5.5-binlog.000001 new file mode 100644 index 0000000000000000000000000000000000000000..9b6f6dce0fb473e424f365d7b75f76145689d8c3 GIT binary patch literal 1037 zcmeyDl$kd(Pb8S1k%58XBM^TDVg?2l22(v#J!3On-^8NKL>DLBl+>isblsf%bg(p5 z0%VM^1up{!gAfA?5C}0a++<*p;s7e<;NW1ws)zo9Yj-7eZUwrO3FP5&AkG0X7{COO zW?^8E0`UD34AEuVWjdYAOPa&Hu%M5Zb6@tWA$3zq4Z+MVcfK6rx84m=vV3va7vIZzcMv%bG zNCuj5pIQz#(Xr6fQP42eQ7|;q1X%(1!7s2CTp;HI!55$uGbo^hftVMV?im;WV&{j6 literal 0 HcmV?d00001 diff --git a/mysql-test/suite/rpl/r/rpl_old_master.result b/mysql-test/suite/rpl/r/rpl_old_master.result new file mode 100644 index 00000000000..df5bbe34256 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_old_master.result @@ -0,0 +1,27 @@ +include/master-slave.inc +[connection master] +include/stop_slave.inc +include/rpl_stop_server.inc [server_number=1] +include/rpl_start_server.inc [server_number=1] +SET @old_parallel= @@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_host='127.0.0.1', master_port=SERVER_MYPORT_1, master_user='root', master_log_file='master-bin.000001', master_log_pos=4; +include/start_slave.inc +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1); +SELECT * FROM t1 ORDER BY a; +a b +1 1 +2 2 +3 4 +4 8 +5 16 +SELECT * FROM t2; +a +1 +include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel; +DROP TABLE t1; +include/start_slave.inc +DROP TABLE t2; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_old_master.test b/mysql-test/suite/rpl/t/rpl_old_master.test new file mode 100644 index 00000000000..8f61d6979cd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_old_master.test @@ -0,0 +1,49 @@ +# Test replicating off old master. +# We simulate old master by copying in pre-generated binlog files from earlier +# server versions. + +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection slave +--source include/stop_slave.inc + +--connection master +--let $datadir= `SELECT @@datadir` + +--let $rpl_server_number= 1 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master-bin.000001 +--copy_file $MYSQL_TEST_DIR/std_data/mariadb-5.5-binlog.000001 $datadir/master-bin.000001 + +--let $rpl_server_number= 1 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc + +--connection slave +SET @old_parallel= @@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=10; +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_1, master_user='root', master_log_file='master-bin.000001', master_log_pos=4; +--source include/start_slave.inc + +--connection master +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1); +--save_master_pos + +--connection slave +--sync_with_master +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2; + +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel; +DROP TABLE t1; +--source include/start_slave.inc + +--connection master +DROP TABLE t2; +--source include/rpl_end.inc diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index cceb6013d6c..12fcef7c866 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -1259,11 +1259,12 @@ abandon_worker_thread(THD *thd, rpl_parallel_thread *cur_thread, do_event() is executed by the sql_driver_thd thread. It's main purpose is to find a thread that can execute the query. - @retval false ok, event was accepted - @retval true error + @retval 0 ok, event was accepted + @retval 1 error + @retval -1 event should be executed serially, in the sql driver thread */ -bool +int rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, ulonglong event_size) { @@ -1277,6 +1278,32 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, bool did_enter_cond= false; const char *old_msg= NULL; + /* Handle master log name change, seen in Rotate_log_event. */ + typ= ev->get_type_code(); + if (unlikely(typ == ROTATE_EVENT)) + { + Rotate_log_event *rev= static_cast(ev); + if ((rev->server_id != global_system_variables.server_id || + rli->replicate_same_server_id) && + !rev->is_relay_log_event() && + !rli->is_in_group()) + { + memcpy(rli->future_event_master_log_name, + rev->new_log_ident, rev->ident_len+1); + } + } + + /* + Execute queries non-parallel if slave_skip_counter is set, as it's is + easier to skip queries in single threaded mode. + */ + if (rli->slave_skip_counter) + return -1; + + /* Execute pre-10.0 event, which have no GTID, in single-threaded mode. */ + if (unlikely(!current) && typ != GTID_EVENT) + return -1; + /* ToDo: what to do with this lock?!? */ mysql_mutex_unlock(&rli->data_lock); @@ -1288,21 +1315,20 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, been partially queued, but after that we will just ignore any further events the SQL driver thread may try to queue, and eventually it will stop. */ - if (((typ= ev->get_type_code()) == GTID_EVENT || - !(is_group_event= Log_event::is_group_event(typ))) && - rli->abort_slave) + is_group_event= Log_event::is_group_event(typ); + if ((typ == GTID_EVENT || !is_group_event) && rli->abort_slave) sql_thread_stopping= true; if (sql_thread_stopping) { delete ev; /* - Return false ("no error"); normal stop is not an error, and otherwise the - error has already been recorded. + Return "no error"; normal stop is not an error, and otherwise the error + has already been recorded. */ - return false; + return 0; } - if (typ == GTID_EVENT || unlikely(!current)) + if (typ == GTID_EVENT) { uint32 domain_id; if (likely(typ == GTID_EVENT)) @@ -1317,7 +1343,7 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, { my_error(ER_OUT_OF_RESOURCES, MYF(MY_WME)); delete ev; - return true; + return 1; } current= e; } @@ -1336,7 +1362,7 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, { /* This means we were killed. The error is already signalled. */ delete ev; - return true; + return 1; } if (!(qev= cur_thread->get_qev(ev, event_size, rli))) @@ -1344,7 +1370,7 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, abandon_worker_thread(rli->sql_driver_thd, cur_thread, &did_enter_cond, old_msg); delete ev; - return true; + return 1; } if (typ == GTID_EVENT) @@ -1357,7 +1383,7 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, abandon_worker_thread(rli->sql_driver_thd, cur_thread, &did_enter_cond, old_msg); delete ev; - return true; + return 1; } /* @@ -1395,7 +1421,7 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, abandon_worker_thread(rli->sql_driver_thd, cur_thread, &did_enter_cond, old_msg); delete ev; - return true; + return 1; } e->current_gco= rgi->gco= gco; } @@ -1409,7 +1435,7 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, e->current_sub_id= rgi->gtid_sub_id; ++e->count_queued_event_groups; } - else if (!is_group_event || !e) + else if (!is_group_event) { my_off_t log_pos; int err; @@ -1418,38 +1444,22 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, Events like ROTATE and FORMAT_DESCRIPTION. Do not run in worker thread. Same for events not preceeded by GTID (we should not see those normally, but they might be from an old master). - - The variable `e' is NULL for the case where the master did not - have GTID, like a MariaDB 5.5 or MySQL master. */ qev->rgi= serial_rgi; - /* Handle master log name change, seen in Rotate_log_event. */ - if (typ == ROTATE_EVENT) - { - Rotate_log_event *rev= static_cast(qev->ev); - if ((rev->server_id != global_system_variables.server_id || - rli->replicate_same_server_id) && - !rev->is_relay_log_event() && - !rli->is_in_group()) - { - memcpy(rli->future_event_master_log_name, - rev->new_log_ident, rev->ident_len+1); - } - } tmp= serial_rgi->is_parallel_exec; serial_rgi->is_parallel_exec= true; err= rpt_handle_event(qev, NULL); serial_rgi->is_parallel_exec= tmp; - log_pos= qev->ev->log_pos; - delete_or_keep_event_post_apply(serial_rgi, typ, qev->ev); + log_pos= ev->log_pos; + delete_or_keep_event_post_apply(serial_rgi, typ, ev); if (err) { cur_thread->free_qev(qev); abandon_worker_thread(rli->sql_driver_thd, cur_thread, &did_enter_cond, old_msg); - return true; + return 1; } /* Queue an empty event, so that the position will be updated in a @@ -1480,5 +1490,5 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, &did_enter_cond, old_msg); mysql_cond_signal(&cur_thread->COND_rpl_thread); - return false; + return 0; } diff --git a/sql/rpl_parallel.h b/sql/rpl_parallel.h index 31a6a035dd8..128ef698240 100644 --- a/sql/rpl_parallel.h +++ b/sql/rpl_parallel.h @@ -225,8 +225,7 @@ struct rpl_parallel { void wait_for_done(THD *thd, Relay_log_info *rli); void stop_during_until(); bool workers_idle(); - bool do_event(rpl_group_info *serial_rgi, Log_event *ev, - ulonglong event_size); + int do_event(rpl_group_info *serial_rgi, Log_event *ev, ulonglong event_size); }; diff --git a/sql/slave.cc b/sql/slave.cc index 29515fb3821..3a6dcf92a8a 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3449,13 +3449,17 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli, update_state_of_relay_log(rli, ev); - /* - Execute queries in parallel, except if slave_skip_counter is set, - as it's is easier to skip queries in single threaded mode. - */ - - if (opt_slave_parallel_threads > 0 && rli->slave_skip_counter == 0) - DBUG_RETURN(rli->parallel.do_event(serial_rgi, ev, event_size)); + if (opt_slave_parallel_threads > 0) + { + int res= rli->parallel.do_event(serial_rgi, ev, event_size); + if (res >= 0) + DBUG_RETURN(res); + /* + Else we proceed to execute the event non-parallel. + This is the case for pre-10.0 events without GTID, and for handling + slave_skip_counter. + */ + } /* For GTID, allocate a new sub_id for the given domain_id. From b5b82108497b5beda3b2fbe98ecea178b5e58076 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 4 Mar 2014 13:10:14 +0100 Subject: [PATCH 11/11] MDEV-5754: MySQL 5.5 slaves cannot replicate from MariaDB 10.0 The problem was when a GTID event was part of a group commit, and so contained a commit id. The code that replaces GTID with a BEGIN event for old slaves did not correctly handle this case. Fix the code so that the GTID with commit id can also be properly replaced with a BEGIN query event. The extra two bytes are in the BEGIN event replaced with a dummy, empty time zone string. --- .../rpl/r/rpl_mariadb_slave_capability.result | 28 ++++++++++- .../rpl/t/rpl_mariadb_slave_capability.test | 50 ++++++++++++++++++- sql/log_event.cc | 30 ++++++++--- sql/log_event.h | 9 ++-- 4 files changed, 106 insertions(+), 11 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result b/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result index 2a7ed37cf9b..12623bdeb3a 100644 --- a/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result +++ b/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result @@ -62,6 +62,32 @@ slave-relay-bin.000007 # Query # # # Dummy ev slave-relay-bin.000007 # Table_map # # table_id: # (test.t1) slave-relay-bin.000007 # Write_rows # # table_id: # flags: STMT_END_F slave-relay-bin.000007 # Query # # COMMIT +*** MDEV-5754: MySQL 5.5 slaves cannot replicate from MariaDB 10.0 *** +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB; +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +INSERT INTO t2 VALUES (1); +SET debug_sync='now WAIT_FOR master_queued1'; +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +INSERT INTO t2 VALUES (2); +SET debug_sync='now WAIT_FOR master_queued2'; +SET debug_sync='now SIGNAL master_cont1'; +SET debug_sync='RESET'; +SET debug_sync='RESET'; +SET debug_sync='RESET'; +show binlog events in 'master-bin.000003' from limit 0, 8; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000003 # Gtid # # BEGIN GTID #-#-# cid=# +master-bin.000003 # Table_map # # table_id: # (test.t2) +master-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000003 # Xid # # COMMIT /* XID */ +master-bin.000003 # Gtid # # BEGIN GTID #-#-# cid=# +master-bin.000003 # Table_map # # table_id: # (test.t2) +master-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000003 # Xid # # COMMIT /* XID */ +SELECT * FROM t2 ORDER BY a; +a +1 +2 # Test that slave which cannot tolerate holes in binlog stream but # knows the event does not get dummy event include/stop_slave.inc @@ -95,5 +121,5 @@ select @@global.replicate_annotate_row_events; set @@global.debug_dbug= @old_slave_dbug; Clean up. set @@global.binlog_checksum = @old_master_binlog_checksum; -DROP TABLE t1; +DROP TABLE t1, t2; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test index 99a371eac44..7a2f5f3e699 100644 --- a/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test +++ b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test @@ -1,6 +1,8 @@ --source include/master-slave.inc --source include/have_debug.inc +--source include/have_debug_sync.inc --source include/have_binlog_format_row.inc +--source include/have_innodb.inc connection master; @@ -71,6 +73,52 @@ let $binlog_start= 0; let $binlog_limit=7,5; --source include/show_relaylog_events.inc + +--echo *** MDEV-5754: MySQL 5.5 slaves cannot replicate from MariaDB 10.0 *** + +# The problem was that for a group commit, we get commit id into the +# GTID event, and there was a bug in the code that replaces GTID with +# dummy that failed when commit id was present. +# +# So setup a group commit in InnoDB. + +--connection master +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB; +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); + +--connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +send INSERT INTO t2 VALUES (1); + +--connection master +SET debug_sync='now WAIT_FOR master_queued1'; + +--connect (con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +send INSERT INTO t2 VALUES (2); + +--connection master +SET debug_sync='now WAIT_FOR master_queued2'; +SET debug_sync='now SIGNAL master_cont1'; + +--connection con1 +REAP; +SET debug_sync='RESET'; +--connection con2 +REAP; +SET debug_sync='RESET'; +--connection master +SET debug_sync='RESET'; +let $binlog_limit= 0, 8; +--source include/show_binlog_events.inc +--save_master_pos + +--connection slave +--sync_with_master +SELECT * FROM t2 ORDER BY a; + + --echo # Test that slave which cannot tolerate holes in binlog stream but --echo # knows the event does not get dummy event @@ -106,6 +154,6 @@ set @@global.debug_dbug= @old_slave_dbug; --echo Clean up. connection master; set @@global.binlog_checksum = @old_master_binlog_checksum; -DROP TABLE t1; +DROP TABLE t1, t2; sync_slave_with_master; --source include/rpl_end.inc diff --git a/sql/log_event.cc b/sql/log_event.cc index 361efe4428e..acdf370cf76 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3639,9 +3639,14 @@ Query_log_event::begin_event(String *packet, ulong ev_offset, DBUG_ASSERT(checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF || checksum_alg == BINLOG_CHECKSUM_ALG_OFF); - /* Currently we only need to replace GTID event. */ - DBUG_ASSERT(data_len == LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN); - if (data_len != LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN) + /* + Currently we only need to replace GTID event. + The length of GTID differs depending on whether it contains commit id. + */ + DBUG_ASSERT(data_len == LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN || + data_len == LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN + 2); + if (data_len != LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN && + data_len != LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN + 2) return 1; flags= uint2korr(p + FLAGS_OFFSET); @@ -3654,9 +3659,22 @@ Query_log_event::begin_event(String *packet, ulong ev_offset, int4store(q + Q_EXEC_TIME_OFFSET, 0); q[Q_DB_LEN_OFFSET]= 0; int2store(q + Q_ERR_CODE_OFFSET, 0); - int2store(q + Q_STATUS_VARS_LEN_OFFSET, 0); - q[Q_DATA_OFFSET]= 0; /* Zero terminator for empty db */ - q+= Q_DATA_OFFSET + 1; + if (data_len == LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN) + { + int2store(q + Q_STATUS_VARS_LEN_OFFSET, 0); + q[Q_DATA_OFFSET]= 0; /* Zero terminator for empty db */ + q+= Q_DATA_OFFSET + 1; + } + else + { + DBUG_ASSERT(data_len == LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN + 2); + /* Put in an empty time_zone_str to take up the extra 2 bytes. */ + int2store(q + Q_STATUS_VARS_LEN_OFFSET, 2); + q[Q_DATA_OFFSET]= Q_TIME_ZONE_CODE; + q[Q_DATA_OFFSET+1]= 0; /* Zero length for empty time_zone_str */ + q[Q_DATA_OFFSET+2]= 0; /* Zero terminator for empty db */ + q+= Q_DATA_OFFSET + 3; + } memcpy(q, "BEGIN", 5); if (checksum_alg == BINLOG_CHECKSUM_ALG_CRC32) diff --git a/sql/log_event.h b/sql/log_event.h index 312a9656d01..415332c46bc 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -3105,12 +3105,15 @@ public: flags 1 byte bitfield Bit 0 set indicates stand-alone event (no terminating COMMIT) + Bit 1 set indicates group commit, and that commit id exists - Reserved - 6 bytes - Reserved bytes, set to 0. Maybe be used for future expansion. + Reserved (no group commit) / commit id (group commit) (see flags bit 1) + 6 bytes / 8 bytes + Reserved bytes, set to 0. Maybe be used for future expansion (no + group commit). OR commit id, same for all GTIDs in the same group + commit (see flags bit 1).