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/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/std_data/mariadb-5.5-binlog.000001 b/mysql-test/std_data/mariadb-5.5-binlog.000001 new file mode 100644 index 00000000000..9b6f6dce0fb Binary files /dev/null and b/mysql-test/std_data/mariadb-5.5-binlog.000001 differ 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/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result b/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result index f6ce29101f8..9c19062255c 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_v1 # # 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'; +include/show_binlog_events.inc +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_v1 # # 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_v1 # # 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/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_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/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/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/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/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), 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/log_event.cc b/sql/log_event.cc index 2b55db5dc78..1e69d5bf1cc 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3736,9 +3736,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); @@ -3751,9 +3756,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) @@ -6779,7 +6797,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) { @@ -6799,10 +6817,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/log_event.h b/sql/log_event.h index cfdc65a2c40..a9d1b08171f 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -3123,12 +3123,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). diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 5947fb70330..154a95c1028 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() { @@ -1230,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) { @@ -1248,6 +1278,32 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, bool did_enter_cond= false; PSI_stage_info old_stage; + /* 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); @@ -1259,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)) @@ -1288,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; } @@ -1307,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))) @@ -1315,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_stage); delete ev; - return true; + return 1; } if (typ == GTID_EVENT) @@ -1328,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_stage); delete ev; - return true; + return 1; } /* @@ -1366,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_stage); delete ev; - return true; + return 1; } e->current_gco= rgi->gco= gco; } @@ -1380,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; @@ -1389,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_stage); - return true; + return 1; } /* Queue an empty event, so that the position will be updated in a @@ -1451,5 +1490,5 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, &did_enter_cond, &old_stage); 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 956a31e4b7f..c4bb407e5eb 100644 --- a/sql/rpl_parallel.h +++ b/sql/rpl_parallel.h @@ -222,10 +222,10 @@ 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); + int 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 399852744f8..0fae3a3bb89 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 25480da79a1..8482924ef87 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, @@ -3427,6 +3434,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); @@ -3454,13 +3462,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. @@ -4371,6 +4383,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); @@ -4542,7 +4555,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 */ { @@ -4568,7 +4581,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 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/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; 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 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; 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; + 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/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); } 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; } } 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