diff options
73 files changed, 1270 insertions, 447 deletions
diff --git a/cmake/plugin.cmake b/cmake/plugin.cmake index ff911008939..e7e9d2a3642 100644 --- a/cmake/plugin.cmake +++ b/cmake/plugin.cmake @@ -26,13 +26,13 @@ INCLUDE(CMakeParseArguments) # [STATIC_OUTPUT_NAME static_name] # [RECOMPILE_FOR_EMBEDDED] # [LINK_LIBRARIES lib1...libN] -# [DEPENDENCIES target1...targetN] +# [DEPENDS target1...targetN] MACRO(MYSQL_ADD_PLUGIN) CMAKE_PARSE_ARGUMENTS(ARG "STORAGE_ENGINE;STATIC_ONLY;MODULE_ONLY;MANDATORY;DEFAULT;DISABLED;RECOMPILE_FOR_EMBEDDED;CLIENT" "MODULE_OUTPUT_NAME;STATIC_OUTPUT_NAME;COMPONENT;CONFIG" - "LINK_LIBRARIES;DEPENDENCIES" + "LINK_LIBRARIES;DEPENDS" ${ARGN} ) IF(NOT WITHOUT_SERVER OR ARG_CLIENT) @@ -111,8 +111,8 @@ MACRO(MYSQL_ADD_PLUGIN) ENDIF() UNSET(${with_var} CACHE) - IF(NOT ARG_DEPENDENCIES) - SET(ARG_DEPENDENCIES) + IF(NOT ARG_DEPENDS) + SET(ARG_DEPENDS) ENDIF() IF(NOT ARG_MODULE_OUTPUT_NAME) @@ -138,7 +138,7 @@ MACRO(MYSQL_ADD_PLUGIN) ADD_LIBRARY(${target} STATIC ${SOURCES}) DTRACE_INSTRUMENT(${target}) - ADD_DEPENDENCIES(${target} GenError ${ARG_DEPENDENCIES}) + ADD_DEPENDENCIES(${target} GenError ${ARG_DEPENDS}) RESTRICT_SYMBOL_EXPORTS(${target}) IF(WITH_EMBEDDED_SERVER) # Embedded library should contain PIC code and be linkable @@ -152,7 +152,7 @@ MACRO(MYSQL_ADD_PLUGIN) SET_TARGET_PROPERTIES(${target}_embedded PROPERTIES COMPILE_DEFINITIONS "EMBEDDED_LIBRARY") ENDIF() - ADD_DEPENDENCIES(${target}_embedded GenError) + ADD_DEPENDENCIES(${target}_embedded GenError ${ARG_DEPENDS}) ENDIF() ENDIF() @@ -213,7 +213,7 @@ MACRO(MYSQL_ADD_PLUGIN) TARGET_LINK_LIBRARIES (${target} "-Wl,--no-undefined") ENDIF() - ADD_DEPENDENCIES(${target} GenError ${ARG_DEPENDENCIES}) + ADD_DEPENDENCIES(${target} GenError ${ARG_DEPENDS}) SET_TARGET_PROPERTIES(${target} PROPERTIES OUTPUT_NAME "${ARG_MODULE_OUTPUT_NAME}") @@ -256,15 +256,20 @@ MACRO(MYSQL_ADD_PLUGIN) INSTALL_MYSQL_TEST("${CMAKE_CURRENT_SOURCE_DIR}/mysql-test/" "plugin/${subpath}") ENDIF() - GET_TARGET_PROPERTY(plugin_type ${target} TYPE) - STRING(REGEX REPLACE "_LIBRARY$" "" plugin_type ${plugin_type}) - STRING(REGEX REPLACE "^NO$" "" plugin_type ${plugin_type}) + IF(TARGET ${target}) + GET_TARGET_PROPERTY(plugin_type ${target} TYPE) + STRING(REPLACE "_LIBRARY" "" plugin_type ${plugin_type}) + SET(have_target 1) + ELSE() + SET(plugin_type) + SET(have_target 0) + ENDIF() IF(ARG_STORAGE_ENGINE) - ADD_FEATURE_INFO(${plugin} PLUGIN_${plugin} "Storage Engine ${plugin_type}") + ADD_FEATURE_INFO(${plugin} ${have_target} "Storage Engine ${plugin_type}") ELSEIF(ARG_CLIENT) - ADD_FEATURE_INFO(${plugin} PLUGIN_${plugin} "Client plugin ${plugin_type}") + ADD_FEATURE_INFO(${plugin} ${have_target} "Client plugin ${plugin_type}") ELSE() - ADD_FEATURE_INFO(${plugin} PLUGIN_${plugin} "Server plugin ${plugin_type}") + ADD_FEATURE_INFO(${plugin} ${have_target} "Server plugin ${plugin_type}") ENDIF() ENDIF(NOT WITHOUT_SERVER OR ARG_CLIENT) ENDMACRO() diff --git a/mysql-test/suite/encryption/r/innodb_import.result b/mysql-test/suite/encryption/r/innodb_import.result new file mode 100644 index 00000000000..54b95ab26d4 --- /dev/null +++ b/mysql-test/suite/encryption/r/innodb_import.result @@ -0,0 +1,22 @@ +# +# MDEV-26131 SEGV in ha_innobase::discard_or_import_tablespace +# +CREATE TABLE t1(f1 int,f2 text)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1, "InnoDB"); +CREATE TABLE t2 LIKE t1; +ALTER TABLE t2 ADD KEY idx (f2(13)); +ALTER TABLE t2 DISCARD TABLESPACE; +FLUSH TABLES t1 FOR EXPORT; +UNLOCK TABLES; +ALTER TABLE t2 IMPORT TABLESPACE; +ERROR HY000: Internal error: Drop all secondary indexes before importing table test/t2 when .cfg file is missing. +ALTER TABLE t2 DROP KEY idx; +Warnings: +Warning 1814 Tablespace has been discarded for table `t2` +ALTER TABLE t2 IMPORT TABLESPACE; +Warnings: +Warning 1810 IO Read error: (2, No such file or directory) Error opening './test/t2.cfg', will attempt to import without schema verification +SELECT * FROM t2; +f1 f2 +1 InnoDB +DROP TABLE t1, t2; diff --git a/mysql-test/suite/encryption/t/innodb_import.combinations b/mysql-test/suite/encryption/t/innodb_import.combinations new file mode 100644 index 00000000000..75458949582 --- /dev/null +++ b/mysql-test/suite/encryption/t/innodb_import.combinations @@ -0,0 +1,7 @@ +[page_compressed] +innodb-compression-default=1 +[encryption] +innodb-encrypt-tables=1 +[page_compressed_encryption] +innodb-compression-default=1 +innodb-encrypt-tables=1 diff --git a/mysql-test/suite/encryption/t/innodb_import.test b/mysql-test/suite/encryption/t/innodb_import.test new file mode 100644 index 00000000000..791a1757878 --- /dev/null +++ b/mysql-test/suite/encryption/t/innodb_import.test @@ -0,0 +1,22 @@ +--source include/have_innodb.inc +-- source include/have_example_key_management_plugin.inc +--echo # +--echo # MDEV-26131 SEGV in ha_innobase::discard_or_import_tablespace +--echo # +let $MYSQLD_DATADIR = `SELECT @@datadir`; +CREATE TABLE t1(f1 int,f2 text)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1, "InnoDB"); +CREATE TABLE t2 LIKE t1; +ALTER TABLE t2 ADD KEY idx (f2(13)); +ALTER TABLE t2 DISCARD TABLESPACE; +FLUSH TABLES t1 FOR EXPORT; +--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t2.ibd +UNLOCK TABLES; +--error ER_INTERNAL_ERROR +ALTER TABLE t2 IMPORT TABLESPACE; + +ALTER TABLE t2 DROP KEY idx; +--replace_regex /opening '.*\/test\//opening '.\/test\// +ALTER TABLE t2 IMPORT TABLESPACE; +SELECT * FROM t2; +DROP TABLE t1, t2; diff --git a/mysql-test/suite/federated/federated_partition.result b/mysql-test/suite/federated/federated_partition.result index c8a61d825b6..374dba515c7 100644 --- a/mysql-test/suite/federated/federated_partition.result +++ b/mysql-test/suite/federated/federated_partition.result @@ -47,6 +47,42 @@ connection slave; drop table federated.t1_1; drop table federated.t1_2; End of 5.1 tests +# +# MDEV-18734 ASAN heap-use-after-free upon sorting by blob column from partitioned table +# +connection slave; +use federated; +create table t1_1 (x int, b text, key(x)); +create table t1_2 (x int, b text, key(x)); +connection master; +create table t1 (x int, b text, key(x)) engine=federated +partition by range columns (x) ( +partition p1 values less than (40) connection='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1_1', +partition pn values less than (maxvalue) connection='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1_2' +); +insert t1 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8); +insert t1 select x + 8, x + 8 from t1; +insert t1 select x + 16, x + 16 from t1; +insert t1 select x + 49, repeat(x + 49, 100) from t1; +flush tables; +# This produces wrong result before MDEV-17573 +select x, left(b, 10) from t1 where x > 30 and x < 60 order by b; +x left(b, 10) +31 31 +32 32 +50 5050505050 +51 5151515151 +52 5252525252 +53 5353535353 +54 5454545454 +55 5555555555 +56 5656565656 +57 5757575757 +58 5858585858 +59 5959595959 +drop table t1; +connection slave; +drop table t1_1, t1_2; connection master; DROP TABLE IF EXISTS federated.t1; DROP DATABASE IF EXISTS federated; diff --git a/mysql-test/suite/federated/federated_partition.test b/mysql-test/suite/federated/federated_partition.test index 47110b5eebf..42f56134279 100644 --- a/mysql-test/suite/federated/federated_partition.test +++ b/mysql-test/suite/federated/federated_partition.test @@ -51,4 +51,29 @@ drop table federated.t1_2; --echo End of 5.1 tests +--echo # +--echo # MDEV-18734 ASAN heap-use-after-free upon sorting by blob column from partitioned table +--echo # +connection slave; +use federated; +create table t1_1 (x int, b text, key(x)); +create table t1_2 (x int, b text, key(x)); +connection master; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval create table t1 (x int, b text, key(x)) engine=federated + partition by range columns (x) ( + partition p1 values less than (40) connection='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1_1', + partition pn values less than (maxvalue) connection='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1_2' +); +insert t1 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8); +insert t1 select x + 8, x + 8 from t1; +insert t1 select x + 16, x + 16 from t1; +insert t1 select x + 49, repeat(x + 49, 100) from t1; +flush tables; +--echo # This produces wrong result before MDEV-17573 +select x, left(b, 10) from t1 where x > 30 and x < 60 order by b; +drop table t1; +connection slave; +drop table t1_1, t1_2; + source include/federated_cleanup.inc; diff --git a/mysql-test/suite/galera/r/galera_split_brain.result b/mysql-test/suite/galera/r/galera_split_brain.result index 08f9060d2a9..bd8c3a5bc44 100644 --- a/mysql-test/suite/galera/r/galera_split_brain.result +++ b/mysql-test/suite/galera/r/galera_split_brain.result @@ -7,9 +7,8 @@ connection node_1; connection node_2; Killing server ... connection node_1; -SET SESSION lock_wait_timeout= 3; CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction connection node_2; connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; disconnect node_2; diff --git a/mysql-test/suite/galera/t/galera_split_brain.test b/mysql-test/suite/galera/t/galera_split_brain.test index ccdfd3fd506..6a822b8f127 100644 --- a/mysql-test/suite/galera/t/galera_split_brain.test +++ b/mysql-test/suite/galera/t/galera_split_brain.test @@ -22,8 +22,7 @@ call mtr.add_suppression("WSREP: TO isolation failed for: "); --source include/kill_galera.inc --connection node_1 -SET SESSION lock_wait_timeout= 3; ---error ER_LOCK_WAIT_TIMEOUT +--error ER_LOCK_DEADLOCK CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; # Reset the master and restart the slave so that post-test checks can run diff --git a/mysql-test/suite/innodb/r/full_crc32_import.result b/mysql-test/suite/innodb/r/full_crc32_import.result index b8ebbb73706..b7f6f1ab09a 100644 --- a/mysql-test/suite/innodb/r/full_crc32_import.result +++ b/mysql-test/suite/innodb/r/full_crc32_import.result @@ -34,19 +34,23 @@ db.opt t1.frm restore: t1 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; +ERROR HY000: Internal error: Drop all secondary indexes before importing table test/t1 when .cfg file is missing. +ALTER TABLE t1 DROP INDEX b; +Warnings: +Warning 1814 Tablespace has been discarded for table `t1` +ALTER TABLE t1 IMPORT TABLESPACE; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `a` int(11) NOT NULL AUTO_INCREMENT, `b` blob DEFAULT NULL, `c` blob DEFAULT NULL, - PRIMARY KEY (`a`), - KEY `b` (`b`(200)) + PRIMARY KEY (`a`) ) ENGINE=InnoDB AUTO_INCREMENT=46 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC UPDATE t1 set b = repeat("de", 100) where b = repeat("cd", 200); explain SELECT a FROM t1 where b = repeat("de", 100); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref b b 203 const # Using where +1 SIMPLE t1 ALL NULL NULL NULL NULL # Using where SELECT a FROM t1 where b = repeat("de", 100); a 3 @@ -108,14 +112,20 @@ ALTER TABLE t1 ROW_FORMAT=DYNAMIC; ALTER TABLE t1 DISCARD TABLESPACE; restore: t1 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; +ERROR HY000: Internal error: Drop all secondary indexes before importing table test/t1 when .cfg file is missing. +ALTER TABLE t1 DROP INDEX idx1; +Warnings: +Warning 1814 Tablespace has been discarded for table `t1` +ALTER TABLE t1 IMPORT TABLESPACE; +Warnings: +Warning 1810 IO Read error: (2, No such file or directory) Error opening './test/t1.cfg', will attempt to import without schema verification SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` int(11) NOT NULL AUTO_INCREMENT, `c2` point NOT NULL, `c3` linestring NOT NULL, - PRIMARY KEY (`c1`), - SPATIAL KEY `idx1` (`c2`) + PRIMARY KEY (`c1`) ) ENGINE=InnoDB AUTO_INCREMENT=14325 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC UPDATE t1 SET C2 = ST_GeomFromText('POINT(0 0)'); SELECT COUNT(*) FROM t1; diff --git a/mysql-test/suite/innodb/r/implicit_gap_lock_convertion.result b/mysql-test/suite/innodb/r/implicit_gap_lock_convertion.result new file mode 100644 index 00000000000..fd197324c3e --- /dev/null +++ b/mysql-test/suite/innodb/r/implicit_gap_lock_convertion.result @@ -0,0 +1,17 @@ +CREATE TABLE t(a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t VALUES (10), (30); +connect con1,localhost,root,,; +SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; +BEGIN; +INSERT INTO t VALUES (20); +SELECT * FROM t WHERE a BETWEEN 10 AND 30; +a +10 +20 +30 +connection default; +SET session innodb_lock_wait_timeout=1; +INSERT INTO t VALUES (15); +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +disconnect con1; +DROP TABLE t; diff --git a/mysql-test/suite/innodb/r/import_corrupted.result b/mysql-test/suite/innodb/r/import_corrupted.result new file mode 100644 index 00000000000..c0474ebbb1d --- /dev/null +++ b/mysql-test/suite/innodb/r/import_corrupted.result @@ -0,0 +1,30 @@ +call mtr.add_suppression("Table `test`.`t2` should have 2 indexes but the tablespace has 1 indexes"); +call mtr.add_suppression("Index for table 't2' is corrupt; try to repair it"); +call mtr.add_suppression("Trying to read page number 23 in space .*, space name test/t2, which is outside the tablespace bounds. Byte offset 0, len 16384"); +CREATE TABLE t1 ( +id INT AUTO_INCREMENT PRIMARY KEY, +not_id INT, +data CHAR(255), +data2 BLOB +) ENGINE=INNODB; +ALTER TABLE t1 MODIFY not_id INT UNIQUE KEY; +connect purge_control,localhost,root,,; +START TRANSACTION WITH CONSISTENT SNAPSHOT; +connection default; +DELETE FROM t1 WHERE id % 2 = 1; +FLUSH TABLES t1 FOR EXPORT; +UNLOCK TABLES; +connection purge_control; +COMMIT; +connection default; +DROP TABLE t1; +CREATE TABLE t2 ( +id INT AUTO_INCREMENT PRIMARY KEY, +not_id INT UNIQUE KEY, +data CHAR(255), +data2 BLOB +) ENGINE=INNODB; +ALTER TABLE t2 DISCARD TABLESPACE; +ALTER TABLE t2 IMPORT TABLESPACE; +ERROR HY000: Index for table 't2' is corrupt; try to repair it +DROP TABLE t2; diff --git a/mysql-test/suite/innodb/r/innodb_information_schema.result b/mysql-test/suite/innodb/r/innodb_information_schema.result index 766d5f47c2d..f8b53f1b2c8 100644 --- a/mysql-test/suite/innodb/r/innodb_information_schema.result +++ b/mysql-test/suite/innodb/r/innodb_information_schema.result @@ -45,7 +45,7 @@ trx_last_foreign_key_error varchar(256) YES NULL trx_is_read_only int(1) NO 0 trx_autocommit_non_locking int(1) NO 0 trx_state trx_weight trx_tables_in_use trx_tables_locked trx_rows_locked trx_rows_modified trx_concurrency_tickets trx_isolation_level trx_unique_checks trx_foreign_key_checks -RUNNING 3 0 1 5 1 0 REPEATABLE READ 1 1 +RUNNING 3 0 1 6 1 0 REPEATABLE READ 1 1 trx_isolation_level trx_unique_checks trx_foreign_key_checks SERIALIZABLE 0 0 trx_state trx_isolation_level trx_last_foreign_key_error diff --git a/mysql-test/suite/innodb/t/full_crc32_import.test b/mysql-test/suite/innodb/t/full_crc32_import.test index 2c11a2423e6..02ce565c7f8 100644 --- a/mysql-test/suite/innodb/t/full_crc32_import.test +++ b/mysql-test/suite/innodb/t/full_crc32_import.test @@ -51,6 +51,9 @@ ib_restore_tablespaces("test", "t1"); EOF --remove_file $MYSQLD_DATADIR/test/t1.cfg +--error ER_INTERNAL_ERROR +ALTER TABLE t1 IMPORT TABLESPACE; +ALTER TABLE t1 DROP INDEX b; --disable_warnings ALTER TABLE t1 IMPORT TABLESPACE; --enable_warnings @@ -127,9 +130,12 @@ ib_restore_tablespaces("test", "t1"); EOF --remove_file $MYSQLD_DATADIR/test/t1.cfg ---disable_warnings +--error ER_INTERNAL_ERROR ALTER TABLE t1 IMPORT TABLESPACE; --enable_warnings +ALTER TABLE t1 DROP INDEX idx1; +ALTER TABLE t1 IMPORT TABLESPACE; +--disable_warnings SHOW CREATE TABLE t1; UPDATE t1 SET C2 = ST_GeomFromText('POINT(0 0)'); SELECT COUNT(*) FROM t1; diff --git a/mysql-test/suite/innodb/t/implicit_gap_lock_convertion.test b/mysql-test/suite/innodb/t/implicit_gap_lock_convertion.test new file mode 100644 index 00000000000..bf2d09ffb2e --- /dev/null +++ b/mysql-test/suite/innodb/t/implicit_gap_lock_convertion.test @@ -0,0 +1,21 @@ +--source include/have_innodb.inc +--source include/count_sessions.inc + +CREATE TABLE t(a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; + +INSERT INTO t VALUES (10), (30); + +--connect (con1,localhost,root,,) +SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; +BEGIN; +INSERT INTO t VALUES (20); +SELECT * FROM t WHERE a BETWEEN 10 AND 30; + +--connection default +SET session innodb_lock_wait_timeout=1; +--error ER_LOCK_WAIT_TIMEOUT +INSERT INTO t VALUES (15); + +--disconnect con1 +DROP TABLE t; +--source include/wait_until_count_sessions.inc diff --git a/mysql-test/suite/innodb/t/import_corrupted.test b/mysql-test/suite/innodb/t/import_corrupted.test new file mode 100644 index 00000000000..22b4bbbdc8b --- /dev/null +++ b/mysql-test/suite/innodb/t/import_corrupted.test @@ -0,0 +1,68 @@ +--source include/have_innodb.inc + +call mtr.add_suppression("Table `test`.`t2` should have 2 indexes but the tablespace has 1 indexes"); +call mtr.add_suppression("Index for table 't2' is corrupt; try to repair it"); +call mtr.add_suppression("Trying to read page number 23 in space .*, space name test/t2, which is outside the tablespace bounds. Byte offset 0, len 16384"); + +let MYSQLD_DATADIR = `SELECT @@datadir`; + +CREATE TABLE t1 ( + id INT AUTO_INCREMENT PRIMARY KEY, + not_id INT, + data CHAR(255), + data2 BLOB +) ENGINE=INNODB; + +--disable_query_log +--let i = 0 +while ($i != 1000) { + eval INSERT INTO t1 VALUES (DEFAULT, $i, REPEAT('b', 255), REPEAT('a', 5000)); + --inc $i +} +--enable_query_log + +ALTER TABLE t1 MODIFY not_id INT UNIQUE KEY; + +connect (purge_control,localhost,root,,); +START TRANSACTION WITH CONSISTENT SNAPSHOT; +connection default; + +DELETE FROM t1 WHERE id % 2 = 1; + +FLUSH TABLES t1 FOR EXPORT; + +--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/tmp.ibd +--copy_file $MYSQLD_DATADIR/test/t1.cfg $MYSQLD_DATADIR/test/tmp.cfg + +perl; +use strict; +die unless open(FILE, "+<$ENV{MYSQLD_DATADIR}/test/tmp.ibd"); +die unless truncate(FILE, 16384*23); +close(FILE); +EOF + +UNLOCK TABLES; +connection purge_control; +COMMIT; +connection default; +DROP TABLE t1; + +CREATE TABLE t2 ( + id INT AUTO_INCREMENT PRIMARY KEY, + not_id INT UNIQUE KEY, + data CHAR(255), + data2 BLOB +) ENGINE=INNODB; + +ALTER TABLE t2 DISCARD TABLESPACE; + +--copy_file $MYSQLD_DATADIR/test/tmp.ibd $MYSQLD_DATADIR/test/t2.ibd +--copy_file $MYSQLD_DATADIR/test/tmp.cfg $MYSQLD_DATADIR/test/t2.cfg + +--error ER_NOT_KEYFILE +ALTER TABLE t2 IMPORT TABLESPACE; + +DROP TABLE t2; + +--remove_file $MYSQLD_DATADIR/test/tmp.ibd +--remove_file $MYSQLD_DATADIR/test/tmp.cfg diff --git a/mysql-test/suite/innodb_gis/r/alter_spatial_index.result b/mysql-test/suite/innodb_gis/r/alter_spatial_index.result index 0264d8cc9a8..ae7f8c08d45 100644 --- a/mysql-test/suite/innodb_gis/r/alter_spatial_index.result +++ b/mysql-test/suite/innodb_gis/r/alter_spatial_index.result @@ -252,6 +252,16 @@ UNLOCK TABLES; ALTER TABLE tab DISCARD TABLESPACE; SELECT c1,ST_Astext(c2),ST_Astext(c4) FROM tab; ERROR HY000: Tablespace has been discarded for table `tab` +ERROR HY000: Internal error: Drop all secondary indexes before importing table test/tab when .cfg file is missing. +Table Create Table +tab CREATE TABLE `tab` ( + `c1` int(11) NOT NULL, + `c2` point NOT NULL, + `c3` linestring NOT NULL, + `c4` polygon NOT NULL, + `c5` geometry NOT NULL, + PRIMARY KEY (`c2`(25)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 CHECK TABLE tab; Table Op Msg_type Msg_text test.tab check status OK @@ -282,9 +292,6 @@ INSERT INTO tab SELECT * FROM tab1; ALTER TABLE tab DROP PRIMARY KEY; affected rows: 1 info: Records: 1 Duplicates: 0 Warnings: 0 -ALTER TABLE tab DROP INDEX idx2; -affected rows: 0 -info: Records: 0 Duplicates: 0 Warnings: 0 SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TEMPORARY TABLE temp_tab AS SELECT * FROM tab where c1 = c2; ERROR HY000: Illegal parameter data types int and geometry for operation '=' @@ -325,18 +332,10 @@ tab CREATE TABLE `tab` ( `c2` point NOT NULL, `c3` linestring NOT NULL, `c4` polygon NOT NULL, - `c5` geometry NOT NULL, - SPATIAL KEY `idx3` (`c3`), - SPATIAL KEY `idx4` (`c4`) COMMENT 'testing spatial index on Polygon', - SPATIAL KEY `idx5` (`c5`) COMMENT 'testing spatial index on Geometry', - KEY `idx6` (`c4`(10)) USING BTREE + `c5` geometry NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 SHOW INDEX FROM tab; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment -tab 1 idx3 1 c3 A # 32 NULL SPATIAL -tab 1 idx4 1 c4 A # 32 NULL SPATIAL testing spatial index on Polygon -tab 1 idx5 1 c5 A # 32 NULL SPATIAL testing spatial index on Geometry -tab 1 idx6 1 c4 A # 10 NULL BTREE DELETE FROM tab; ALTER TABLE tab ADD PRIMARY KEY(c2); affected rows: 0 @@ -357,20 +356,12 @@ tab CREATE TABLE `tab` ( `c5` geometry NOT NULL, PRIMARY KEY (`c2`(25)), UNIQUE KEY `const_1` (`c2`(25)), - SPATIAL KEY `idx3` (`c3`), - SPATIAL KEY `idx4` (`c4`) COMMENT 'testing spatial index on Polygon', - SPATIAL KEY `idx5` (`c5`) COMMENT 'testing spatial index on Geometry', - KEY `idx6` (`c4`(10)) USING BTREE, SPATIAL KEY `idx2` (`c2`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 SHOW INDEX FROM tab; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment tab 0 PRIMARY 1 c2 A # 25 NULL BTREE tab 0 const_1 1 c2 A # 25 NULL BTREE -tab 1 idx3 1 c3 A # 32 NULL SPATIAL -tab 1 idx4 1 c4 A # 32 NULL SPATIAL testing spatial index on Polygon -tab 1 idx5 1 c5 A # 32 NULL SPATIAL testing spatial index on Geometry -tab 1 idx6 1 c4 A # 10 NULL BTREE tab 1 idx2 1 c2 A # 32 NULL SPATIAL INSERT INTO tab(c1,c2,c3,c4,c5) VALUES(1,ST_GeomFromText('POINT(10 10)'),ST_GeomFromText('LINESTRING(5 5,20 20,30 30)'), @@ -399,20 +390,12 @@ tab CREATE TABLE `tab` ( `c5` geometry NOT NULL, PRIMARY KEY (`c5`(10)), UNIQUE KEY `const_1` (`c5`(10)), - SPATIAL KEY `idx3` (`c3`), - SPATIAL KEY `idx4` (`c4`) COMMENT 'testing spatial index on Polygon', - SPATIAL KEY `idx5` (`c5`) COMMENT 'testing spatial index on Geometry', - KEY `idx6` (`c4`(10)) USING BTREE, SPATIAL KEY `idx2` (`c2`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 SHOW INDEX FROM tab; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment tab 0 PRIMARY 1 c5 A # 10 NULL BTREE tab 0 const_1 1 c5 A # 10 NULL BTREE -tab 1 idx3 1 c3 A # 32 NULL SPATIAL -tab 1 idx4 1 c4 A # 32 NULL SPATIAL testing spatial index on Polygon -tab 1 idx5 1 c5 A # 32 NULL SPATIAL testing spatial index on Geometry -tab 1 idx6 1 c4 A # 10 NULL BTREE tab 1 idx2 1 c2 A # 32 NULL SPATIAL INSERT INTO tab(c1,c2,c3,c4,c5) VALUES(1,ST_GeomFromText('POINT(10 10)'),ST_GeomFromText('LINESTRING(5 5,20 20,30 30)'), diff --git a/mysql-test/suite/innodb_gis/t/alter_spatial_index.test b/mysql-test/suite/innodb_gis/t/alter_spatial_index.test index b7eac432fcc..de1d301245f 100644 --- a/mysql-test/suite/innodb_gis/t/alter_spatial_index.test +++ b/mysql-test/suite/innodb_gis/t/alter_spatial_index.test @@ -277,8 +277,17 @@ SELECT c1,ST_Astext(c2),ST_Astext(c4) FROM tab; --disable_query_log +--error ER_INTERNAL_ERROR ALTER TABLE tab IMPORT TABLESPACE; +ALTER TABLE tab DROP INDEX idx2; +ALTER TABLE tab DROP INDEX idx3; +ALTER TABLE tab DROP INDEX idx4; +ALTER TABLE tab DROP INDEX idx5; +ALTER TABLE tab DROP INDEX idx6; + +SHOW CREATE TABLE tab; +ALTER TABLE tab IMPORT TABLESPACE; --enable_query_log CHECK TABLE tab; @@ -308,7 +317,6 @@ INSERT INTO tab SELECT * FROM tab1; --enable_info ALTER TABLE tab DROP PRIMARY KEY; -ALTER TABLE tab DROP INDEX idx2; --disable_info # Check spatial index on temp tables diff --git a/mysql-test/suite/vcol/r/partition.result b/mysql-test/suite/vcol/r/partition.result index bd1353fa145..d7c5052b72a 100644 --- a/mysql-test/suite/vcol/r/partition.result +++ b/mysql-test/suite/vcol/r/partition.result @@ -28,3 +28,76 @@ set statement sql_mode= '' for update t1 set i= 1, v= 2; Warnings: Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored drop table t1; +# +# MDEV-18734 ASAN heap-use-after-free in my_strnxfrm_simple_internal upon update on versioned partitioned table +# +# Cover queue_fix() in ha_partition::handle_ordered_index_scan() +create or replace table t1 ( +x int auto_increment primary key, +b text, v mediumtext as (b) virtual, +index (v(10)) +) partition by range columns (x) ( +partition p1 values less than (3), +partition p2 values less than (6), +partition p3 values less than (9), +partition p4 values less than (12), +partition p5 values less than (15), +partition p6 values less than (17), +partition p7 values less than (19), +partition p8 values less than (21), +partition p9 values less than (23), +partition p10 values less than (25), +partition p11 values less than (27), +partition p12 values less than (29), +partition p13 values less than (31), +partition p14 values less than (33), +partition p15 values less than (35), +partition pn values less than (maxvalue)); +insert into t1 (b) values +(repeat('q', 8192)), (repeat('z', 8192)), (repeat('a', 8192)), (repeat('b', 8192)), +(repeat('x', 8192)), (repeat('y', 8192)); +insert t1 (b) select b from t1; +insert t1 (b) select b from t1; +insert t1 (b) select b from t1; +insert t1 (b) select b from t1; +select x, left(b, 10), left(v, 10) from t1 where x > 30 and x < 60 order by v; +x left(b, 10) left(v, 10) +33 aaaaaaaaaa aaaaaaaaaa +39 aaaaaaaaaa aaaaaaaaaa +45 aaaaaaaaaa aaaaaaaaaa +51 aaaaaaaaaa aaaaaaaaaa +57 aaaaaaaaaa aaaaaaaaaa +34 bbbbbbbbbb bbbbbbbbbb +40 bbbbbbbbbb bbbbbbbbbb +46 bbbbbbbbbb bbbbbbbbbb +52 bbbbbbbbbb bbbbbbbbbb +58 bbbbbbbbbb bbbbbbbbbb +31 qqqqqqqqqq qqqqqqqqqq +37 qqqqqqqqqq qqqqqqqqqq +43 qqqqqqqqqq qqqqqqqqqq +49 qqqqqqqqqq qqqqqqqqqq +55 qqqqqqqqqq qqqqqqqqqq +35 xxxxxxxxxx xxxxxxxxxx +41 xxxxxxxxxx xxxxxxxxxx +47 xxxxxxxxxx xxxxxxxxxx +53 xxxxxxxxxx xxxxxxxxxx +59 xxxxxxxxxx xxxxxxxxxx +36 yyyyyyyyyy yyyyyyyyyy +42 yyyyyyyyyy yyyyyyyyyy +48 yyyyyyyyyy yyyyyyyyyy +54 yyyyyyyyyy yyyyyyyyyy +32 zzzzzzzzzz zzzzzzzzzz +38 zzzzzzzzzz zzzzzzzzzz +44 zzzzzzzzzz zzzzzzzzzz +50 zzzzzzzzzz zzzzzzzzzz +56 zzzzzzzzzz zzzzzzzzzz +update t1 set b= 'bar' where v > 'a' limit 20; +drop table t1; +# Cover return_top_record() in ha_partition::handle_ordered_index_scan() +create table t1 (x int primary key, b tinytext, v text as (b) virtual) +partition by range columns (x) ( +partition p1 values less than (4), +partition pn values less than (maxvalue)); +insert into t1 (x, b) values (1, ''), (2, ''), (3, 'a'), (4, 'b'); +update t1 set b= 'bar' where x > 0 order by v limit 2; +drop table t1; diff --git a/mysql-test/suite/vcol/t/partition.test b/mysql-test/suite/vcol/t/partition.test index 889724fb1c5..408990b20a6 100644 --- a/mysql-test/suite/vcol/t/partition.test +++ b/mysql-test/suite/vcol/t/partition.test @@ -30,3 +30,51 @@ subpartition by hash(v) subpartitions 3 ( insert t1 set i= 0; set statement sql_mode= '' for update t1 set i= 1, v= 2; drop table t1; + +--echo # +--echo # MDEV-18734 ASAN heap-use-after-free in my_strnxfrm_simple_internal upon update on versioned partitioned table +--echo # +--echo # Cover queue_fix() in ha_partition::handle_ordered_index_scan() +create or replace table t1 ( + x int auto_increment primary key, + b text, v mediumtext as (b) virtual, + index (v(10)) +) partition by range columns (x) ( + partition p1 values less than (3), + partition p2 values less than (6), + partition p3 values less than (9), + partition p4 values less than (12), + partition p5 values less than (15), + partition p6 values less than (17), + partition p7 values less than (19), + partition p8 values less than (21), + partition p9 values less than (23), + partition p10 values less than (25), + partition p11 values less than (27), + partition p12 values less than (29), + partition p13 values less than (31), + partition p14 values less than (33), + partition p15 values less than (35), + partition pn values less than (maxvalue)); +insert into t1 (b) values +(repeat('q', 8192)), (repeat('z', 8192)), (repeat('a', 8192)), (repeat('b', 8192)), +(repeat('x', 8192)), (repeat('y', 8192)); + +insert t1 (b) select b from t1; +insert t1 (b) select b from t1; +insert t1 (b) select b from t1; +insert t1 (b) select b from t1; + +select x, left(b, 10), left(v, 10) from t1 where x > 30 and x < 60 order by v; +update t1 set b= 'bar' where v > 'a' limit 20; + +drop table t1; + +--echo # Cover return_top_record() in ha_partition::handle_ordered_index_scan() +create table t1 (x int primary key, b tinytext, v text as (b) virtual) +partition by range columns (x) ( + partition p1 values less than (4), + partition pn values less than (maxvalue)); +insert into t1 (x, b) values (1, ''), (2, ''), (3, 'a'), (4, 'b'); +update t1 set b= 'bar' where x > 0 order by v limit 2; +drop table t1; diff --git a/mysql-test/suite/versioning/r/foreign.result b/mysql-test/suite/versioning/r/foreign.result index 288909bbc37..2dbceebb539 100644 --- a/mysql-test/suite/versioning/r/foreign.result +++ b/mysql-test/suite/versioning/r/foreign.result @@ -445,3 +445,16 @@ pk f1 f2 left(f3, 4) check_row_ts(row_start, row_end) 1 8 8 SHOR HISTORICAL ROW 2 8 8 LONG HISTORICAL ROW drop table t1; +# +# MDEV-21555 Assertion secondary index is out of sync on delete from versioned table +# +create table t1 (a int, b int as (a + 1) virtual, key(a)) engine=innodb with system versioning; +set foreign_key_checks= off; +insert into t1 (a) values (1), (2); +alter table t1 add foreign key (b) references t1 (a), algorithm=copy; +update t1 set a= null where a = 1; +delete from t1 where a is null; +set foreign_key_checks= on; +delete history from t1; +delete from t1; +drop table t1; diff --git a/mysql-test/suite/versioning/t/foreign.test b/mysql-test/suite/versioning/t/foreign.test index 4143cd59048..20c35028565 100644 --- a/mysql-test/suite/versioning/t/foreign.test +++ b/mysql-test/suite/versioning/t/foreign.test @@ -476,4 +476,22 @@ select pk, f1, f2, left(f3, 4), check_row_ts(row_start, row_end) from t1 for sys # cleanup drop table t1; +--echo # +--echo # MDEV-21555 Assertion secondary index is out of sync on delete from versioned table +--echo # +create table t1 (a int, b int as (a + 1) virtual, key(a)) engine=innodb with system versioning; + +set foreign_key_checks= off; +insert into t1 (a) values (1), (2); +alter table t1 add foreign key (b) references t1 (a), algorithm=copy; +update t1 set a= null where a = 1; +delete from t1 where a is null; +set foreign_key_checks= on; + +delete history from t1; +delete from t1; + +# cleanup +drop table t1; + --source suite/versioning/common_finish.inc diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh index 562f9dc3aac..67244a7c622 100644 --- a/scripts/wsrep_sst_common.sh +++ b/scripts/wsrep_sst_common.sh @@ -1010,7 +1010,13 @@ check_port() lsof -Pnl -i ":$port" 2>/dev/null | \ grep -q -E "^($utils)[^[:space:]]*[[:space:]]+$pid[[:space:]].*\\(LISTEN\\)" && rc=0 elif [ $sockstat_available -ne 0 ]; then - sockstat -p "$port" 2>/dev/null | \ + local opts='-p' + if [ "$OS" = 'FreeBSD' ]; then + # sockstat on FreeBSD requires the "-s" option + # to display the connection state: + opts='-sp' + fi + sockstat "$opts" "$port" 2>/dev/null | \ grep -q -E "[[:space:]]+($utils)[^[:space:]]*[[:space:]]+$pid[[:space:]].*[[:space:]]LISTEN" && rc=0 elif [ $ss_available -ne 0 ]; then ss -nlpH "( sport = :$port )" 2>/dev/null | \ diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index 46804c9dce4..562b9b929f2 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -166,7 +166,8 @@ get_keys() fi if [ -z "$ekey" -a ! -r "$ekeyfile" ]; then - wsrep_log_error "FATAL: Either key or keyfile must be readable" + wsrep_log_error "FATAL: Either key must be specified " \ + "or keyfile must be readable" exit 3 fi @@ -448,9 +449,30 @@ encgroups='--mysqld|sst|xtrabackup' check_server_ssl_config() { - tcert=$(parse_cnf "$encgroups" 'ssl-ca') - tpem=$(parse_cnf "$encgroups" 'ssl-cert') - tkey=$(parse_cnf "$encgroups" 'ssl-key') + # backward-compatible behavior: + tcert=$(parse_cnf 'sst' 'tca') + tpem=$(parse_cnf 'sst' 'tcert') + tkey=$(parse_cnf 'sst' 'tkey') + # reading new ssl configuration options: + local tcert2=$(parse_cnf "$encgroups" 'ssl-ca') + local tpem2=$(parse_cnf "$encgroups" 'ssl-cert') + local tkey2=$(parse_cnf "$encgroups" 'ssl-key') + # if there are no old options, then we take new ones: + if [ -z "$tcert" -a -z "$tpem" -a -z "$tkey" ]; then + tcert="$tcert2" + tpem="$tpem2" + tkey="$tkey2" + # checking for presence of the new-style SSL configuration: + elif [ -n "$tcert2" -o -n "$tpem2" -o -n "$tkey2" ]; then + if [ "$tcert" != "$tcert2" -o \ + "$tpem" != "$tpem2" -o \ + "$tkey" != "$tkey2" ] + then + wsrep_log_info "new ssl configuration options (ssl-ca, ssl-cert " \ + "and ssl-key) are ignored by SST due to presence " \ + "of the tca, tcert and/or tkey in the [sst] section" + fi + fi } read_cnf() @@ -463,18 +485,10 @@ read_cnf() if [ $encrypt -eq 0 -o $encrypt -ge 2 ] then - if [ "$tmode" != 'DISABLED' -o $encrypt -ge 2 ] - then - tcert=$(parse_cnf 'sst' 'tca') - tpem=$(parse_cnf 'sst' 'tcert') - tkey=$(parse_cnf 'sst' 'tkey') + if [ "$tmode" != 'DISABLED' -o $encrypt -ge 2 ]; then + check_server_ssl_config fi if [ "$tmode" != 'DISABLED' ]; then - # backward-incompatible behavior - if [ -z "$tpem" -a -z "$tkey" -a -z "$tcert" ]; then - # no old-style SSL config in [sst] - check_server_ssl_config - fi if [ 0 -eq $encrypt -a -n "$tpem" -a -n "$tkey" ] then encrypt=3 # enable cert/key SSL encyption @@ -489,7 +503,11 @@ read_cnf() ealgo=$(parse_cnf "$encgroups" 'encrypt-algo') eformat=$(parse_cnf "$encgroups" 'encrypt-format' 'openssl') ekey=$(parse_cnf "$encgroups" 'encrypt-key') - ekeyfile=$(parse_cnf "$encgroups" 'encrypt-key-file') + # The keyfile should be read only when the key + # is not specified or empty: + if [ -z "$ekey" ]; then + ekeyfile=$(parse_cnf "$encgroups" 'encrypt-key-file') + fi fi wsrep_log_info "SSL configuration: CA='$tcert', CERT='$tpem'," \ diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index fc9f5017937..d90e87b68f2 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -93,7 +93,15 @@ check_pid_and_port() else local filter='([^[:space:]]+[[:space:]]+){4}[^[:space:]]+' if [ $sockstat_available -eq 1 ]; then - port_info=$(sockstat -p "$port" 2>/dev/null | \ + local opts='-p' + if [ "$OS" = 'FreeBSD' ]; then + # sockstat on FreeBSD requires the "-s" option + # to display the connection state: + opts='-sp' + # in addition, sockstat produces an additional column: + filter='([^[:space:]]+[[:space:]]+){5}[^[:space:]]+' + fi + port_info=$(sockstat "$opts" "$port" 2>/dev/null | \ grep -E '[[:space:]]LISTEN' | grep -o -E "$filter") else port_info=$(ss -nlpH "( sport = :$port )" 2>/dev/null | \ @@ -388,7 +396,7 @@ EOF # Use deltaxfer only for WAN inv=$(basename "$0") WHOLE_FILE_OPT="" - if [ "${inv%wsrep_sst_rsync_wan*}" != "$inv" ]; then + if [ "${inv%wsrep_sst_rsync_wan*}" = "$inv" ]; then WHOLE_FILE_OPT="--whole-file" fi diff --git a/sql/field.cc b/sql/field.cc index b391234b866..8b82077f452 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. - Copyright (c) 2008, 2020, MariaDB + Copyright (c) 2008, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -8556,6 +8556,7 @@ int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs) rc= well_formed_copy_with_check((char*) value.ptr(), (uint) new_length, cs, from, length, length, true, ©_len); + value.length(copy_len); Field_blob::store_length(copy_len); bmove(ptr+packlength,(uchar*) &tmp,sizeof(char*)); diff --git a/sql/field.h b/sql/field.h index 477c64727b3..5c2ba4c5c84 100644 --- a/sql/field.h +++ b/sql/field.h @@ -4030,6 +4030,12 @@ public: uchar *new_ptr, uint32 length, uchar *new_null_ptr, uint new_null_bit); void sql_type(String &str) const; + /** + Copy blob buffer into internal storage "value" and update record pointer. + + @retval true Memory allocation error + @retval false Success + */ inline bool copy() { uchar *tmp= get_ptr(); @@ -4042,6 +4048,33 @@ public: memcpy(ptr+packlength, &tmp, sizeof(char*)); return 0; } + void swap(String &inout, bool set_read_value) + { + if (set_read_value) + read_value.swap(inout); + else + value.swap(inout); + } + /** + Return pointer to blob cache or NULL if not cached. + */ + String * cached(bool *set_read_value) + { + char *tmp= (char *) get_ptr(); + if (!value.is_empty() && tmp == value.ptr()) + { + *set_read_value= false; + return &value; + } + + if (!read_value.is_empty() && tmp == read_value.ptr()) + { + *set_read_value= true; + return &read_value; + } + + return NULL; + } /* store value for the duration of the current read record */ inline void swap_value_and_read_value() { diff --git a/sql/filesort.cc b/sql/filesort.cc index aa25474be1a..ee19dfcb386 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -597,6 +597,15 @@ const char* dbug_print_table_row(TABLE *table) } +const char* dbug_print_row(TABLE *table, uchar *rec) +{ + table->move_fields(table->field, rec, table->record[0]); + const char* ret= dbug_print_table_row(table); + table->move_fields(table->field, table->record[0], rec); + return ret; +} + + /* Print a text, SQL-like record representation into dbug trace. diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 50b9149ef0c..c8d5d68b5d6 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -5289,58 +5289,68 @@ bool ha_partition::init_record_priority_queue() /* Initialize the ordered record buffer. */ - if (!m_ordered_rec_buffer) - { - size_t alloc_len; - uint used_parts= bitmap_bits_set(&m_part_info->read_partitions); - - if (used_parts == 0) /* Do nothing since no records expected. */ - DBUG_RETURN(false); + size_t alloc_len; + uint used_parts= bitmap_bits_set(&m_part_info->read_partitions); - /* Allocate record buffer for each used partition. */ - m_priority_queue_rec_len= m_rec_length + PARTITION_BYTES_IN_POS; - if (!m_using_extended_keys) - m_priority_queue_rec_len += get_open_file_sample()->ref_length; - alloc_len= used_parts * m_priority_queue_rec_len; - /* Allocate a key for temporary use when setting up the scan. */ - alloc_len+= table_share->max_key_length; + if (used_parts == 0) /* Do nothing since no records expected. */ + DBUG_RETURN(false); - if (!(m_ordered_rec_buffer= (uchar*)my_malloc(alloc_len, MYF(MY_WME)))) - DBUG_RETURN(true); + /* Allocate record buffer for each used partition. */ + m_priority_queue_rec_len= m_rec_length + ORDERED_REC_OFFSET; + if (!m_using_extended_keys) + m_priority_queue_rec_len+= get_open_file_sample()->ref_length; + alloc_len= used_parts * m_priority_queue_rec_len; + /* Allocate a key for temporary use when setting up the scan. */ + alloc_len+= table_share->max_key_length; + Ordered_blob_storage **blob_storage; + Ordered_blob_storage *objs; + const size_t n_all= used_parts * table->s->blob_fields; + + if (!my_multi_malloc(MYF(MY_WME), &m_ordered_rec_buffer, alloc_len, + &blob_storage, n_all * sizeof *blob_storage, + &objs, n_all * sizeof *objs, NULL)) + DBUG_RETURN(true); - /* - We set-up one record per partition and each record has 2 bytes in - front where the partition id is written. This is used by ordered - index_read. - We also set-up a reference to the first record for temporary use in - setting up the scan. - */ - char *ptr= (char*) m_ordered_rec_buffer; - uint i; - for (i= bitmap_get_first_set(&m_part_info->read_partitions); - i < m_tot_parts; - i= bitmap_get_next_set(&m_part_info->read_partitions, i)) + /* + We set-up one record per partition and each record has 2 bytes in + front where the partition id is written. This is used by ordered + index_read. + We also set-up a reference to the first record for temporary use in + setting up the scan. + */ + char *ptr= (char*) m_ordered_rec_buffer; + uint i; + for (i= bitmap_get_first_set(&m_part_info->read_partitions); + i < m_tot_parts; + i= bitmap_get_next_set(&m_part_info->read_partitions, i)) + { + DBUG_PRINT("info", ("init rec-buf for part %u", i)); + if (table->s->blob_fields) { - DBUG_PRINT("info", ("init rec-buf for part %u", i)); - int2store(ptr, i); - ptr+= m_priority_queue_rec_len; + for (uint j= 0; j < table->s->blob_fields; ++j, ++objs) + blob_storage[j]= new (objs) Ordered_blob_storage; + *((Ordered_blob_storage ***) ptr)= blob_storage; + blob_storage+= table->s->blob_fields; } - m_start_key.key= (const uchar*)ptr; + int2store(ptr + sizeof(String **), i); + ptr+= m_priority_queue_rec_len; + } + m_start_key.key= (const uchar*)ptr; - /* Initialize priority queue, initialized to reading forward. */ - int (*cmp_func)(void *, uchar *, uchar *); - void *cmp_arg= (void*) this; - if (!m_using_extended_keys && !(table_flags() & HA_SLOW_CMP_REF)) - cmp_func= cmp_key_rowid_part_id; - else - cmp_func= cmp_key_part_id; - DBUG_PRINT("info", ("partition queue_init(1) used_parts: %u", used_parts)); - if (init_queue(&m_queue, used_parts, 0, 0, cmp_func, cmp_arg, 0, 0)) - { - my_free(m_ordered_rec_buffer); - m_ordered_rec_buffer= NULL; - DBUG_RETURN(true); - } + /* Initialize priority queue, initialized to reading forward. */ + int (*cmp_func)(void *, uchar *, uchar *); + void *cmp_arg= (void*) this; + if (!m_using_extended_keys && !(table_flags() & HA_SLOW_CMP_REF)) + cmp_func= cmp_key_rowid_part_id; + else + cmp_func= cmp_key_part_id; + DBUG_PRINT("info", ("partition queue_init(1) used_parts: %u", used_parts)); + if (init_queue(&m_queue, used_parts, ORDERED_PART_NUM_OFFSET, + 0, cmp_func, cmp_arg, 0, 0)) + { + my_free(m_ordered_rec_buffer); + m_ordered_rec_buffer= NULL; + DBUG_RETURN(true); } DBUG_RETURN(false); } @@ -5355,6 +5365,20 @@ void ha_partition::destroy_record_priority_queue() DBUG_ENTER("ha_partition::destroy_record_priority_queue"); if (m_ordered_rec_buffer) { + if (table->s->blob_fields) + { + char *ptr= (char *) m_ordered_rec_buffer; + for (uint i= bitmap_get_first_set(&m_part_info->read_partitions); + i < m_tot_parts; + i= bitmap_get_next_set(&m_part_info->read_partitions, i)) + { + Ordered_blob_storage **blob_storage= *((Ordered_blob_storage ***) ptr); + for (uint b= 0; b < table->s->blob_fields; ++b) + blob_storage[b]->blob.free(); + ptr+= m_priority_queue_rec_len; + } + } + delete_queue(&m_queue); my_free(m_ordered_rec_buffer); m_ordered_rec_buffer= NULL; @@ -5582,12 +5606,10 @@ static int cmp_part_ids(uchar *ref1, uchar *ref2) extern "C" int cmp_key_part_id(void *ptr, uchar *ref1, uchar *ref2) { ha_partition *file= (ha_partition*)ptr; - int res; - if ((res= key_rec_cmp(file->m_curr_key_info, ref1 + PARTITION_BYTES_IN_POS, - ref2 + PARTITION_BYTES_IN_POS))) - { + if (int res= key_rec_cmp(file->m_curr_key_info, + ref1 + PARTITION_BYTES_IN_POS, + ref2 + PARTITION_BYTES_IN_POS)) return res; - } return cmp_part_ids(ref1, ref2); } @@ -6836,6 +6858,48 @@ int ha_partition::pre_ft_end() } +void ha_partition::swap_blobs(uchar * rec_buf, Ordered_blob_storage ** storage, bool restore) +{ + uint *ptr, *end; + uint blob_n= 0; + table->move_fields(table->field, rec_buf, table->record[0]); + for (ptr= table->s->blob_field, end= ptr + table->s->blob_fields; + ptr != end; ++ptr, ++blob_n) + { + DBUG_ASSERT(*ptr < table->s->fields); + Field_blob *blob= (Field_blob*) table->field[*ptr]; + DBUG_ASSERT(blob->flags & BLOB_FLAG); + DBUG_ASSERT(blob->field_index == *ptr); + if (!bitmap_is_set(table->read_set, *ptr) || blob->is_null()) + continue; + + Ordered_blob_storage &s= *storage[blob_n]; + + if (restore) + { + /* + We protect only blob cache (value or read_value). If the cache was + empty that doesn't mean the blob was empty. Blobs allocated by a + storage engine should work just fine. + */ + if (!s.blob.is_empty()) + blob->swap(s.blob, s.set_read_value); + } + else + { + bool set_read_value; + String *cached= blob->cached(&set_read_value); + if (cached) + { + cached->swap(s.blob); + s.set_read_value= set_read_value; + } + } + } + table->move_fields(table->field, table->record[0], rec_buf); +} + + /** Initialize a full text search using the extended API. @@ -7549,8 +7613,8 @@ int ha_partition::handle_ordered_index_scan(uchar *buf, bool reverse_order) { DBUG_PRINT("info", ("reading from part %u (scan_type: %u)", i, m_index_scan_type)); - DBUG_ASSERT(i == uint2korr(part_rec_buf_ptr)); - uchar *rec_buf_ptr= part_rec_buf_ptr + PARTITION_BYTES_IN_POS; + DBUG_ASSERT(i == uint2korr(part_rec_buf_ptr + ORDERED_PART_NUM_OFFSET)); + uchar *rec_buf_ptr= part_rec_buf_ptr + ORDERED_REC_OFFSET; handler *file= m_file[i]; switch (m_index_scan_type) { @@ -7630,6 +7694,12 @@ int ha_partition::handle_ordered_index_scan(uchar *buf, bool reverse_order) Initialize queue without order first, simply insert */ queue_element(&m_queue, j++)= part_rec_buf_ptr; + if (table->s->blob_fields) + { + Ordered_blob_storage **storage= + *((Ordered_blob_storage ***) part_rec_buf_ptr); + swap_blobs(rec_buf_ptr, storage, false); + } } else if (error == HA_ERR_KEY_NOT_FOUND) { @@ -7672,7 +7742,7 @@ int ha_partition::handle_ordered_index_scan(uchar *buf, bool reverse_order) DBUG_PRINT("info", ("partition !bitmap_is_set(&m_mrr_used_partitions, i)")); continue; } - DBUG_ASSERT(i == uint2korr(part_rec_buf_ptr)); + DBUG_ASSERT(i == uint2korr(part_rec_buf_ptr + ORDERED_PART_NUM_OFFSET)); if (smallest_range_seq == m_stock_range_seq[i]) { m_stock_range_seq[i]= 0; @@ -7719,12 +7789,17 @@ void ha_partition::return_top_record(uchar *buf) { uint part_id; uchar *key_buffer= queue_top(&m_queue); - uchar *rec_buffer= key_buffer + PARTITION_BYTES_IN_POS; + uchar *rec_buffer= key_buffer + ORDERED_REC_OFFSET; DBUG_ENTER("ha_partition::return_top_record"); DBUG_PRINT("enter", ("partition this: %p", this)); - part_id= uint2korr(key_buffer); + part_id= uint2korr(key_buffer + ORDERED_PART_NUM_OFFSET); memcpy(buf, rec_buffer, m_rec_length); + if (table->s->blob_fields) + { + Ordered_blob_storage **storage= *((Ordered_blob_storage ***) key_buffer); + swap_blobs(buf, storage, true); + } m_last_part= part_id; DBUG_PRINT("info", ("partition m_last_part: %u", m_last_part)); m_top_entry= part_id; @@ -7776,7 +7851,7 @@ int ha_partition::handle_ordered_index_scan_key_not_found() This partition is used and did return HA_ERR_KEY_NOT_FOUND in index_read_map. */ - curr_rec_buf= part_buf + PARTITION_BYTES_IN_POS; + curr_rec_buf= part_buf + ORDERED_REC_OFFSET; error= m_file[i]->ha_index_next(curr_rec_buf); /* HA_ERR_KEY_NOT_FOUND is not allowed from index_next! */ DBUG_ASSERT(error != HA_ERR_KEY_NOT_FOUND); @@ -7827,7 +7902,8 @@ int ha_partition::handle_ordered_next(uchar *buf, bool is_next_same) DBUG_RETURN(HA_ERR_END_OF_FILE); uint part_id= m_top_entry; - uchar *rec_buf= queue_top(&m_queue) + PARTITION_BYTES_IN_POS; + uchar *part_rec_buf_ptr= queue_top(&m_queue); + uchar *rec_buf= part_rec_buf_ptr + ORDERED_REC_OFFSET; handler *file; if (m_key_not_found) @@ -7869,7 +7945,16 @@ int ha_partition::handle_ordered_next(uchar *buf, bool is_next_same) if (m_index_scan_type == partition_read_range) { error= file->read_range_next(); - memcpy(rec_buf, table->record[0], m_rec_length); + if (likely(!error)) + { + memcpy(rec_buf, table->record[0], m_rec_length); + if (table->s->blob_fields) + { + Ordered_blob_storage **storage= + *((Ordered_blob_storage ***) part_rec_buf_ptr); + swap_blobs(rec_buf, storage, false); + } + } } else if (m_index_scan_type == partition_read_multi_range) { @@ -7906,6 +7991,11 @@ int ha_partition::handle_ordered_next(uchar *buf, bool is_next_same) DBUG_PRINT("info", ("m_mrr_range_current->id: %u", m_mrr_range_current->id)); memcpy(rec_buf, table->record[0], m_rec_length); + if (table->s->blob_fields) + { + Ordered_blob_storage **storage= *((Ordered_blob_storage ***) part_rec_buf_ptr); + swap_blobs(rec_buf, storage, false); + } if (((PARTITION_KEY_MULTI_RANGE *) m_range_info[part_id])->id != m_mrr_range_current->id) { @@ -7956,9 +8046,8 @@ int ha_partition::handle_ordered_next(uchar *buf, bool is_next_same) DBUG_PRINT("info",("partition !bitmap_is_set(&m_mrr_used_partitions, i)")); continue; } - DBUG_PRINT("info",("partition uint2korr: %u", - uint2korr(part_rec_buf_ptr))); - DBUG_ASSERT(i == uint2korr(part_rec_buf_ptr)); + DBUG_ASSERT(i == uint2korr(part_rec_buf_ptr + + ORDERED_PART_NUM_OFFSET)); DBUG_PRINT("info", ("partition m_stock_range_seq[%u]: %u", i, m_stock_range_seq[i])); if (smallest_range_seq == m_stock_range_seq[i]) @@ -8047,7 +8136,7 @@ int ha_partition::handle_ordered_prev(uchar *buf) DBUG_RETURN(HA_ERR_END_OF_FILE); uint part_id= m_top_entry; - uchar *rec_buf= queue_top(&m_queue) + PARTITION_BYTES_IN_POS; + uchar *rec_buf= queue_top(&m_queue) + ORDERED_REC_OFFSET; handler *file= m_file[part_id]; if (unlikely((error= file->ha_index_prev(rec_buf)))) diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 240d71447ec..8b2c42d94bc 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -21,7 +21,17 @@ #include "sql_partition.h" /* part_id_range, partition_element */ #include "queues.h" /* QUEUE */ +struct Ordered_blob_storage +{ + String blob; + bool set_read_value; + Ordered_blob_storage() : set_read_value(false) + {} +}; + #define PARTITION_BYTES_IN_POS 2 +#define ORDERED_PART_NUM_OFFSET sizeof(Ordered_blob_storage **) +#define ORDERED_REC_OFFSET (ORDERED_PART_NUM_OFFSET + PARTITION_BYTES_IN_POS) /** Struct used for partition_name_hash */ @@ -927,6 +937,7 @@ private: int handle_ordered_next(uchar * buf, bool next_same); int handle_ordered_prev(uchar * buf); void return_top_record(uchar * buf); + void swap_blobs(uchar* rec_buf, Ordered_blob_storage ** storage, bool restore); public: /* ------------------------------------------------------------------------- diff --git a/sql/handler.cc b/sql/handler.cc index 757fa95a9a3..6b8c39cb0c4 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. - Copyright (c) 2009, 2021, MariaDB Corporation. + Copyright (c) 2009, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1946,7 +1946,7 @@ int ha_rollback_trans(THD *thd, bool all) if (thd->is_error()) { WSREP_DEBUG("ha_rollback_trans(%lld, %s) rolled back: %s: %s; is_real %d", - thd->thread_id, all?"TRUE":"FALSE", wsrep_thd_query(thd), + thd->thread_id, all?"TRUE":"FALSE", WSREP_QUERY(thd), thd->get_stmt_da()->message(), is_real_trans); } (void) wsrep_after_rollback(thd, all); diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index c703533f799..798c5d502db 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -375,7 +375,7 @@ public: const char *func_name() const { return mode_insert ? - (mode_replace ? "json_set" : "json_insert") : "json_update"; + (mode_replace ? "json_set" : "json_insert") : "json_replace"; } Item *get_copy(THD *thd) { return get_item_copy<Item_func_json_insert>(thd, this); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 3040aeba4ba..28bf77c94e8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -5228,8 +5228,8 @@ extern "C" bool thd_is_strict_mode(const MYSQL_THD thd) */ void thd_get_query_start_data(THD *thd, char *buf) { - LEX_CSTRING field_name; - Field_timestampf f((uchar *)buf, NULL, 0, Field::NONE, &field_name, NULL, 6); + Field_timestampf f((uchar *)buf, nullptr, 0, Field::NONE, &empty_clex_str, + nullptr, 6); f.store_TIME(thd->query_start(), thd->query_start_sec_part()); } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index cbd815eb8fd..e04062d66d5 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. - Copyright (c) 2010, 2021, MariaDB Corporation + Copyright (c) 2010, 2019, MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -4782,7 +4782,7 @@ bool select_create::send_eof() { WSREP_DEBUG("select_create commit failed, thd: %llu err: %s %s", thd->thread_id, - wsrep_thd_transaction_state_str(thd), wsrep_thd_query(thd)); + wsrep_thd_transaction_state_str(thd), WSREP_QUERY(thd)); mysql_mutex_unlock(&thd->LOCK_thd_data); abort_result_set(); DBUG_RETURN(true); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 1ec5d0b0550..c6db441220e 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2998,7 +2998,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) prepared statement */ Query_arena *arena= thd->stmt_arena; - const uint n_elems= (n_sum_items + + const size_t n_elems= (n_sum_items + n_child_sum_items + item_list.elements + select_n_reserved + @@ -3006,7 +3006,8 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) select_n_where_fields + order_group_num + hidden_bit_fields + - fields_in_window_functions) * 5; + fields_in_window_functions) * (size_t) 5; + DBUG_ASSERT(n_elems % 5 == 0); if (!ref_pointer_array.is_null()) { /* diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8999397fee7..9e78a1a95e2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7845,7 +7845,7 @@ static bool wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(act))); }); WSREP_DEBUG("wsrep retrying AC query: %lu %s", - thd->wsrep_retry_counter, wsrep_thd_query(thd)); + thd->wsrep_retry_counter, WSREP_QUERY(thd)); wsrep_prepare_for_autocommit_retry(thd, rawbuf, length, parser_state); if (thd->lex->explain) delete_explain_query(thd->lex); @@ -7859,7 +7859,7 @@ static bool wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, is_autocommit, thd->wsrep_retry_counter, thd->variables.wsrep_retry_autocommit, - wsrep_thd_query(thd)); + WSREP_QUERY(thd)); my_error(ER_LOCK_DEADLOCK, MYF(0)); thd->reset_kill_query(); thd->wsrep_retry_counter= 0; // reset diff --git a/sql/sql_view.cc b/sql/sql_view.cc index c81b5db0d26..9d4ba09f1b3 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -837,7 +837,7 @@ int mariadb_fix_view(THD *thd, TABLE_LIST *view, bool wrong_checksum, if ((view->md5.str= (char *)thd->alloc(32 + 1)) == NULL) DBUG_RETURN(HA_ADMIN_FAILED); } - view->calc_md5(view->md5.str); + view->calc_md5(const_cast<char*>(view->md5.str)); view->md5.length= 32; } view->mariadb_version= MYSQL_VERSION_ID; diff --git a/sql/table.cc b/sql/table.cc index 4ed47998ecc..d7e892b1dfd 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5297,12 +5297,12 @@ void TABLE::reset_item_list(List<Item> *item_list, uint skip) const buffer buffer for md5 writing */ -void TABLE_LIST::calc_md5(const char *buffer) +void TABLE_LIST::calc_md5(char *buffer) { uchar digest[16]; compute_md5_hash(digest, select_stmt.str, select_stmt.length); - sprintf((char *) buffer, + sprintf(buffer, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], diff --git a/sql/table.h b/sql/table.h index 05add349fb0..a674f7953ef 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2652,7 +2652,7 @@ struct TABLE_LIST List<String> *partition_names; #endif /* WITH_PARTITION_STORAGE_ENGINE */ - void calc_md5(const char *buffer); + void calc_md5(char *buffer); int view_check_option(THD *thd, bool ignore_failure); bool create_field_translation(THD *thd); bool setup_underlying(THD *thd); diff --git a/sql/wsrep_client_service.cc b/sql/wsrep_client_service.cc index f045e5d271a..89621619a23 100644 --- a/sql/wsrep_client_service.cc +++ b/sql/wsrep_client_service.cc @@ -1,4 +1,4 @@ -/* Copyright 2018-2021 Codership Oy <info@codership.com> +/* Copyright 2018 Codership Oy <info@codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -109,14 +109,14 @@ int Wsrep_client_service::prepare_data_for_replication() "affected rows: %llu, " "changed tables: %d, " "sql_log_bin: %d", - wsrep_thd_query(m_thd), + WSREP_QUERY(m_thd), m_thd->get_stmt_da()->affected_rows(), stmt_has_updated_trans_table(m_thd), m_thd->variables.sql_log_bin); } else { - WSREP_DEBUG("empty rbr buffer, query: %s", wsrep_thd_query(m_thd)); + WSREP_DEBUG("empty rbr buffer, query: %s", WSREP_QUERY(m_thd)); } } DBUG_RETURN(0); diff --git a/sql/wsrep_high_priority_service.cc b/sql/wsrep_high_priority_service.cc index 452242dfd23..0da71c3eda5 100644 --- a/sql/wsrep_high_priority_service.cc +++ b/sql/wsrep_high_priority_service.cc @@ -1,4 +1,4 @@ -/* Copyright 2018-2021 Codership Oy <info@codership.com> +/* Copyright 2018 Codership Oy <info@codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -379,16 +379,6 @@ int Wsrep_high_priority_service::apply_toi(const wsrep::ws_meta& ws_meta, WSREP_DEBUG("Wsrep_high_priority_service::apply_toi: %lld", client_state.toi_meta().seqno().get()); - DBUG_EXECUTE_IF("sync.wsrep_apply_toi", - { - const char act[]= - "now " - "SIGNAL sync.wsrep_apply_toi_reached " - "WAIT_FOR signal.wsrep_apply_toi"; - DBUG_ASSERT(!debug_sync_set_action(thd, - STRING_WITH_LEN(act))); - };); - int ret= wsrep_apply_events(thd, m_rli, data.data(), data.size()); if (ret != 0 || thd->wsrep_has_ignored_error) { @@ -437,15 +427,6 @@ int Wsrep_high_priority_service::log_dummy_write_set(const wsrep::ws_handle& ws_ DBUG_PRINT("info", ("Wsrep_high_priority_service::log_dummy_write_set: seqno=%lld", ws_meta.seqno().get())); - DBUG_EXECUTE_IF("sync.wsrep_log_dummy_write_set", - { - const char act[]= - "now " - "SIGNAL sync.wsrep_log_dummy_write_set_reached "; - DBUG_ASSERT(!debug_sync_set_action(m_thd, - STRING_WITH_LEN(act))); - };); - if (ws_meta.ordered()) { wsrep::client_state& cs(m_thd->wsrep_cs()); @@ -677,7 +658,7 @@ Wsrep_replayer_service::~Wsrep_replayer_service() DBUG_ASSERT(0); WSREP_ERROR("trx_replay failed for: %d, schema: %s, query: %s", m_replay_status, - orig_thd->db.str, wsrep_thd_query(orig_thd)); + orig_thd->db.str, WSREP_QUERY(orig_thd)); unireg_abort(1); } } diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index bf1e4e32b49..cabf066abf4 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1,4 +1,4 @@ -/* Copyright 2008-2021 Codership Oy <http://www.codership.com> +/* Copyright 2008-2015 Codership Oy <http://www.codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2008,10 +2008,10 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, { DBUG_ASSERT(thd->variables.wsrep_OSU_method == WSREP_OSU_TOI); - WSREP_DEBUG("TOI Begin for %s", wsrep_thd_query(thd)); + WSREP_DEBUG("TOI Begin for %s", WSREP_QUERY(thd)); if (wsrep_can_run_in_toi(thd, db, table, table_list) == false) { - WSREP_DEBUG("No TOI for %s", wsrep_thd_query(thd)); + WSREP_DEBUG("No TOI for %s", WSREP_QUERY(thd)); return 1; } @@ -2039,7 +2039,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, /* non replicated DDL, affecting temporary tables only */ WSREP_DEBUG("TO isolation skipped, sql: %s." "Only temporary tables affected.", - wsrep_thd_query(thd)); + WSREP_QUERY(thd)); if (buf) my_free(buf); return -1; } @@ -2054,7 +2054,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, { DBUG_ASSERT(cs.current_error()); WSREP_DEBUG("to_execute_start() failed for %llu: %s, seqno: %lld", - thd->thread_id, wsrep_thd_query(thd), + thd->thread_id, WSREP_QUERY(thd), (long long)wsrep_thd_trx_seqno(thd)); /* jump to error handler in mysql_execute_command() */ @@ -2065,32 +2065,15 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, "Maximum size exceeded.", ret, (thd->db.str ? thd->db.str : "(null)"), - wsrep_thd_query(thd)); + WSREP_QUERY(thd)); my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_SIZE_EXCEEDED); break; - case wsrep::e_deadlock_error: - WSREP_WARN("TO isolation failed for: %d, schema: %s, sql: %s. " - "Deadlock error.", - ret, - (thd->db.str ? thd->db.str : "(null)"), - wsrep_thd_query(thd)); - my_error(ER_LOCK_DEADLOCK, MYF(0)); - break; - case wsrep::e_timeout_error: - WSREP_WARN("TO isolation failed for: %d, schema: %s, sql: %s. " - "Operation timed out.", - ret, - (thd->db.str ? thd->db.str : "(null)"), - wsrep_thd_query(thd)); - my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0)); - break; default: WSREP_WARN("TO isolation failed for: %d, schema: %s, sql: %s. " - "Check your wsrep connection state and retry the query.", + "Check wsrep connection state and retry the query.", ret, (thd->db.str ? thd->db.str : "(null)"), - wsrep_thd_query(thd)); - + WSREP_QUERY(thd)); if (!thd->is_error()) { my_error(ER_LOCK_DEADLOCK, MYF(0), "WSREP replication failed. Check " @@ -2123,19 +2106,19 @@ static void wsrep_TOI_end(THD *thd) { if (!ret) { WSREP_DEBUG("TO END: %lld: %s", - client_state.toi_meta().seqno().get(), wsrep_thd_query(thd)); + client_state.toi_meta().seqno().get(), WSREP_QUERY(thd)); } else { WSREP_WARN("TO isolation end failed for: %d, sql: %s", - ret, wsrep_thd_query(thd)); + ret, WSREP_QUERY(thd)); } } static int wsrep_RSU_begin(THD *thd, const char *db_, const char *table_) { WSREP_DEBUG("RSU BEGIN: %lld, : %s", wsrep_thd_trx_seqno(thd), - wsrep_thd_query(thd)); + WSREP_QUERY(thd)); if (thd->wsrep_cs().begin_rsu(5000)) { WSREP_WARN("RSU begin failed"); @@ -2150,7 +2133,7 @@ static int wsrep_RSU_begin(THD *thd, const char *db_, const char *table_) static void wsrep_RSU_end(THD *thd) { WSREP_DEBUG("RSU END: %lld : %s", wsrep_thd_trx_seqno(thd), - wsrep_thd_query(thd)); + WSREP_QUERY(thd)); if (thd->wsrep_cs().end_rsu()) { WSREP_WARN("Failed to end RSU, server may need to be restarted"); @@ -2192,7 +2175,7 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_, if (wsrep_debug && thd->mdl_context.has_locks()) { WSREP_DEBUG("thread holds MDL locks at TI begin: %s %llu", - wsrep_thd_query(thd), thd->thread_id); + WSREP_QUERY(thd), thd->thread_id); } /* @@ -2208,6 +2191,13 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_, thd->variables.auto_increment_increment= 1; } + /* + TOI operations will ignore provided lock_wait_timeout and restore it + after operation is done. + */ + thd->variables.saved_lock_wait_timeout= thd->variables.lock_wait_timeout; + thd->variables.lock_wait_timeout= LONG_TIMEOUT; + if (thd->variables.wsrep_on && wsrep_thd_is_local(thd)) { switch (thd->variables.wsrep_OSU_method) { @@ -2223,19 +2213,8 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_, ret= -1; break; } - switch (ret) { - case 0: /* wsrep_TOI_begin sould set toi mode */ - if (thd->variables.wsrep_OSU_method == WSREP_OSU_TOI) - { - /* - TOI operations ignore the provided lock_wait_timeout once replicated, - and restore it after operation is done. - */ - thd->variables.saved_lock_wait_timeout= thd->variables.lock_wait_timeout; - thd->variables.lock_wait_timeout= LONG_TIMEOUT; - } - break; + case 0: /* wsrep_TOI_begin sould set toi mode */ break; case 1: /* TOI replication skipped, treat as success */ ret= 0; @@ -2254,9 +2233,10 @@ void wsrep_to_isolation_end(THD *thd) DBUG_ASSERT(wsrep_thd_is_local_toi(thd) || wsrep_thd_is_in_rsu(thd)); + thd->variables.lock_wait_timeout= thd->variables.saved_lock_wait_timeout; + if (wsrep_thd_is_local_toi(thd)) { - thd->variables.lock_wait_timeout= thd->variables.saved_lock_wait_timeout; DBUG_ASSERT(thd->variables.wsrep_OSU_method == WSREP_OSU_TOI); wsrep_TOI_end(thd); } diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index db3e9b09b51..748d93c72aa 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -1,4 +1,4 @@ -/* Copyright 2008-2021 Codership Oy <http://www.codership.com> +/* Copyright 2008-2017 Codership Oy <http://www.codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -289,6 +289,8 @@ static inline bool wsrep_cluster_address_exists() return wsrep_cluster_address && wsrep_cluster_address[0]; } +#define WSREP_QUERY(thd) (thd->query()) + extern my_bool wsrep_ready_get(); extern void wsrep_ready_wait(); diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index 2e02110d697..d8f3d8959e0 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -340,20 +340,11 @@ int wsrep_abort_thd(THD *bf_thd_ptr, THD *victim_thd_ptr, my_bool signal) DBUG_RETURN(1); } -bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd) +bool wsrep_bf_abort(const THD* bf_thd, THD* victim_thd) { WSREP_LOG_THD(bf_thd, "BF aborter before"); WSREP_LOG_THD(victim_thd, "victim before"); - - DBUG_EXECUTE_IF("sync.wsrep_bf_abort", - { - const char act[]= - "now " - "SIGNAL sync.wsrep_bf_abort_reached " - "WAIT_FOR signal.wsrep_bf_abort"; - DBUG_ASSERT(!debug_sync_set_action(bf_thd, - STRING_WITH_LEN(act))); - };); + wsrep::seqno bf_seqno(bf_thd->wsrep_trx().ws_meta().seqno()); if (WSREP(victim_thd) && !victim_thd->wsrep_trx().active()) { @@ -371,8 +362,6 @@ bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd) } bool ret; - wsrep::seqno bf_seqno(bf_thd->wsrep_trx().ws_meta().seqno()); - if (wsrep_thd_is_toi(bf_thd)) { ret= victim_thd->wsrep_cs().total_order_bf_abort(bf_seqno); diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h index 560dbbdab44..d24d8e6358f 100644 --- a/sql/wsrep_thd.h +++ b/sql/wsrep_thd.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2021 Codership Oy <info@codership.com> +/* Copyright (C) 2013 Codership Oy <info@codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -87,7 +87,7 @@ int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff, bool wsrep_create_appliers(long threads, bool mutex_protected=false); void wsrep_create_rollbacker(); -bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd); +bool wsrep_bf_abort(const THD*, THD*); int wsrep_abort_thd(THD *bf_thd_ptr, THD *victim_thd_ptr, my_bool signal); extern void wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); @@ -292,7 +292,7 @@ static inline void wsrep_log_thd(const THD *thd, (thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->message() : "") #ifdef WSREP_THD_LOG_QUERIES , thd->lex->sql_command, - wsrep_thd_query(thd) + WSREP_QUERY(thd) #endif /* WSREP_OBSERVER_LOG_QUERIES */ ); } diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index cd7b9bdf870..e4cfd0d89c9 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -1,4 +1,4 @@ -/* Copyright 2008-2021 Codership Oy <http://www.codership.com> +/* Copyright 2008-2015 Codership Oy <http://www.codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -794,7 +794,7 @@ bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var) ret= Wsrep_server_state::instance().provider().desync(); if (ret) { WSREP_WARN ("SET desync failed %d for schema: %s, query: %s", ret, - thd->db.str, wsrep_thd_query(thd)); + thd->db.str, WSREP_QUERY(thd)); my_error (ER_CANNOT_USER, MYF(0), "'desync'", thd->query()); return true; } diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index a1c54d10776..f53f07b79b6 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -1,5 +1,5 @@ # Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. -# Copyright (c) 2014, 2019, MariaDB Corporation. +# Copyright (c) 2014, 2021, MariaDB Corporation. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index aca02ea3998..dd08b3e6b63 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -3237,7 +3237,7 @@ func_exit: @param[in,out] page page to remove @param[in] index index tree @param[in,out] mtr mini-transaction */ -void +dberr_t btr_level_list_remove_func( ulint space, ulint zip_size, @@ -3280,6 +3280,10 @@ btr_level_list_remove_func( page_id_t(space, next_page_no), zip_size, RW_X_LATCH, index, mtr); + if (!next_block) { + return DB_ERROR; + } + page_t* next_page = buf_block_get_frame(next_block); #ifdef UNIV_BTR_DEBUG @@ -3292,6 +3296,8 @@ btr_level_list_remove_func( buf_block_get_page_zip(next_block), prev_page_no, mtr); } + + return DB_SUCCESS; } /****************************************************************//** @@ -3777,8 +3783,11 @@ retry: btr_search_drop_page_hash_index(block); /* Remove the page from the level list */ - btr_level_list_remove(index->table->space_id, - zip_size, page, index, mtr); + if (DB_SUCCESS != btr_level_list_remove(index->table->space_id, + zip_size, page, index, + mtr)) { + goto err_exit; + } if (dict_index_is_spatial(index)) { rec_t* my_rec = father_cursor.page_cur.rec; @@ -3907,8 +3916,11 @@ retry: #endif /* UNIV_BTR_DEBUG */ /* Remove the page from the level list */ - btr_level_list_remove(index->table->space_id, - zip_size, page, index, mtr); + if (DB_SUCCESS != btr_level_list_remove(index->table->space_id, + zip_size, page, index, + mtr)) { + goto err_exit; + } ut_ad(btr_node_ptr_get_child_page_no( btr_cur_get_rec(&father_cursor), offsets) @@ -4313,8 +4325,8 @@ btr_discard_page( } /* Remove the page from the level list */ - btr_level_list_remove(index->table->space_id, zip_size, - page, index, mtr); + ut_a(DB_SUCCESS == btr_level_list_remove(index->table->space_id, + zip_size, page, index, mtr)); #ifdef UNIV_ZIP_DEBUG { diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index aeb5e2aaa9c..3f03b7a13e6 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -335,10 +335,12 @@ btr_cur_latch_leaves( zip_size, RW_X_LATCH, cursor->index, mtr); latch_leaves.blocks[2] = get_block; #ifdef UNIV_BTR_DEBUG - ut_a(page_is_comp(get_block->frame) - == page_is_comp(page)); - ut_a(btr_page_get_prev(get_block->frame) - == page_get_page_no(page)); + if (get_block) { + ut_a(page_is_comp(get_block->frame) + == page_is_comp(page)); + ut_a(btr_page_get_prev(get_block->frame) + == page_get_page_no(page)); + } #endif /* UNIV_BTR_DEBUG */ if (spatial) { cursor->rtr_info->tree_blocks[ diff --git a/storage/innobase/btr/btr0defragment.cc b/storage/innobase/btr/btr0defragment.cc index b22d9f8323d..ea58d2f5fe1 100644 --- a/storage/innobase/btr/btr0defragment.cc +++ b/storage/innobase/btr/btr0defragment.cc @@ -485,9 +485,10 @@ btr_defragment_merge_pages( lock_update_merge_left(to_block, orig_pred, from_block); btr_search_drop_page_hash_index(from_block); - btr_level_list_remove( + + ut_a(DB_SUCCESS == btr_level_list_remove( index->table->space_id, - zip_size, from_page, index, mtr); + zip_size, from_page, index, mtr)); btr_page_get_father(index, from_block, mtr, &parent); btr_cur_node_ptr_delete(&parent, mtr); /* btr_blob_dbg_remove(from_page, index, diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 771e273e8ea..679ce7e8b7e 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -968,8 +968,7 @@ bool buf_is_zeroes(span<const byte> buf) /** Check if a page is corrupt. @param[in] check_lsn whether the LSN should be checked @param[in] read_buf database page -@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 -@param[in] space tablespace +@param[in] fsp_flags tablespace flags @return whether the page is corrupted */ bool buf_page_is_corrupted( @@ -4396,6 +4395,10 @@ loop: } } + if (local_err == DB_IO_ERROR) { + return NULL; + } + ib::fatal() << "Unable to read page " << page_id << " into the buffer pool after " << BUF_PAGE_READ_MAX_RETRIES diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index 67f42bf8ff0..1ea3070cbda 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -189,7 +189,8 @@ buf_read_page_low( if (UNIV_UNLIKELY(*err != DB_SUCCESS)) { if (IORequest::ignore_missing(type) - || *err == DB_TABLESPACE_DELETED) { + || *err == DB_TABLESPACE_DELETED + || *err == DB_IO_ERROR) { buf_read_page_handle_error(bpage); return(0); } diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index e058876a4d3..ffba161aa04 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -3990,27 +3990,30 @@ fil_node_complete_io(fil_node_t* node, const IORequest& type) } } -/** Report information about an invalid page access. */ -static -void -fil_report_invalid_page_access( - ulint block_offset, /*!< in: block offset */ - ulint space_id, /*!< in: space id */ - const char* space_name, /*!< in: space name */ - ulint byte_offset, /*!< in: byte offset */ - ulint len, /*!< in: I/O length */ - bool is_read) /*!< in: I/O type */ +/** Compose error message about an invalid page access. +@param[in] block_offset block offset +@param[in] space_id space id +@param[in] space_name space name +@param[in] byte_offset byte offset +@param[in] len I/O length +@param[in] is_read I/O type +@return std::string with error message */ +static std::string fil_invalid_page_access_msg(size_t block_offset, + size_t space_id, + const char *space_name, + size_t byte_offset, size_t len, + bool is_read) { - ib::fatal() - << "Trying to " << (is_read ? "read" : "write") - << " page number " << block_offset << " in" - " space " << space_id << ", space name " << space_name << "," - " which is outside the tablespace bounds. Byte offset " - << byte_offset << ", len " << len << - (space_id == 0 && !srv_was_started - ? "Please check that the configuration matches" - " the InnoDB system tablespace location (ibdata files)" - : ""); + std::stringstream ss; + ss << "Trying to " << (is_read ? "read" : "write") << " page number " + << block_offset << " in space " << space_id << ", space name " + << space_name << ", which is outside the tablespace bounds. Byte offset " + << byte_offset << ", len " << len + << (space_id == 0 && !srv_was_started + ? "Please check that the configuration matches" + " the InnoDB system tablespace location (ibdata files)" + : ""); + return ss.str(); } inline void IORequest::set_fil_node(fil_node_t* node) @@ -4154,7 +4157,17 @@ fil_io( return(DB_ERROR); } - fil_report_invalid_page_access( + if (space->purpose == FIL_TYPE_IMPORT) { + mutex_exit(&fil_system.mutex); + ib::error() << fil_invalid_page_access_msg( + page_id.page_no(), page_id.space(), + space->name, byte_offset, len, + req_type.is_read()); + + return DB_IO_ERROR; + } + + ib::fatal() << fil_invalid_page_access_msg( page_id.page_no(), page_id.space(), space->name, byte_offset, len, req_type.is_read()); @@ -4221,7 +4234,7 @@ fil_io( return(DB_ERROR); } - fil_report_invalid_page_access( + ib::fatal() << fil_invalid_page_access_msg( page_id.page_no(), page_id.space(), space->name, byte_offset, len, req_type.is_read()); } diff --git a/storage/innobase/fil/fil0pagecompress.cc b/storage/innobase/fil/fil0pagecompress.cc index 1d38f9dc6b7..21b148223f6 100644 --- a/storage/innobase/fil/fil0pagecompress.cc +++ b/storage/innobase/fil/fil0pagecompress.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (C) 2013, 2020, MariaDB Corporation. +Copyright (C) 2013, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -597,6 +597,7 @@ ulint fil_page_decompress_for_non_full_crc32( /** Decompress a page that may be subject to page_compressed compression. @param[in,out] tmp_buf temporary buffer (of innodb_page_size) @param[in,out] buf possibly compressed page buffer +@param[in] flags tablespace flags @return size of the compressed data @retval 0 if decompression failed @retval srv_page_size if the page was not compressed */ diff --git a/storage/innobase/fts/fts0config.cc b/storage/innobase/fts/fts0config.cc index 9e2b40911ae..f95159dc5b7 100644 --- a/storage/innobase/fts/fts0config.cc +++ b/storage/innobase/fts/fts0config.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -97,7 +97,7 @@ fts_config_get_value( fts_table->suffix = "CONFIG"; fts_get_table_name(fts_table, table_name); - pars_info_bind_id(info, true, "table_name", table_name); + pars_info_bind_id(info, "table_name", table_name); graph = fts_parse_sql( fts_table, @@ -217,7 +217,7 @@ fts_config_set_value( fts_table->suffix = "CONFIG"; fts_get_table_name(fts_table, table_name, dict_locked); - pars_info_bind_id(info, true, "table_name", table_name); + pars_info_bind_id(info, "table_name", table_name); graph = fts_parse_sql( fts_table, info, @@ -245,7 +245,7 @@ fts_config_set_value( info, "value", value->f_str, value->f_len); fts_get_table_name(fts_table, table_name, dict_locked); - pars_info_bind_id(info, true, "table_name", table_name); + pars_info_bind_id(info, "table_name", table_name); graph = fts_parse_sql( fts_table, info, diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index ede9546713c..6454135b29f 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -483,7 +483,7 @@ cleanup: pars_info_t* info = pars_info_create(); - pars_info_bind_id(info, TRUE, "table_stopword", stopword_table_name); + pars_info_bind_id(info, "table_stopword", stopword_table_name); pars_info_bind_function(info, "my_func", fts_read_stopword, stopword_info); @@ -1912,7 +1912,7 @@ fts_create_common_tables( fts_table.suffix = "CONFIG"; fts_get_table_name(&fts_table, fts_name, true); - pars_info_bind_id(info, true, "config_table", fts_name); + pars_info_bind_id(info, "config_table", fts_name); graph = fts_parse_sql_no_dict_lock( info, fts_config_table_insert_values_sql); @@ -2640,7 +2640,7 @@ retry: info, "my_func", fts_fetch_store_doc_id, doc_id); fts_get_table_name(&fts_table, table_name); - pars_info_bind_id(info, true, "config_table", table_name); + pars_info_bind_id(info, "config_table", table_name); graph = fts_parse_sql( &fts_table, info, @@ -2768,7 +2768,7 @@ fts_update_sync_doc_id( fts_get_table_name(&fts_table, fts_name, table->fts->dict_locked); - pars_info_bind_id(info, true, "table_name", fts_name); + pars_info_bind_id(info, "table_name", fts_name); graph = fts_parse_sql( &fts_table, info, @@ -2911,7 +2911,7 @@ fts_delete( fts_table.suffix = "DELETED"; fts_get_table_name(&fts_table, table_name); - pars_info_bind_id(info, true, "deleted", table_name); + pars_info_bind_id(info, "deleted", table_name); graph = fts_parse_sql( &fts_table, @@ -3717,7 +3717,7 @@ fts_doc_fetch_by_doc_id( pars_info_bind_function(info, "my_func", callback, arg); select_str = fts_get_select_columns_str(index, info, info->heap); - pars_info_bind_id(info, TRUE, "table_name", index->table->name.m_name); + pars_info_bind_id(info, "table_name", index->table->name.m_name); if (!get_doc || !get_doc->get_document_graph) { if (option == FTS_FETCH_DOC_BY_ID_EQUAL) { @@ -3824,7 +3824,7 @@ fts_write_node( info = pars_info_create(); fts_get_table_name(fts_table, table_name); - pars_info_bind_id(info, true, "index_table_name", table_name); + pars_info_bind_id(info, "index_table_name", table_name); } pars_info_bind_varchar_literal(info, "token", word->f_str, word->f_len); @@ -3899,7 +3899,7 @@ fts_sync_add_deleted_cache( &fts_table, "DELETED_CACHE", FTS_COMMON_TABLE, sync->table); fts_get_table_name(&fts_table, table_name); - pars_info_bind_id(info, true, "table_name", table_name); + pars_info_bind_id(info, "table_name", table_name); graph = fts_parse_sql( &fts_table, @@ -4904,7 +4904,7 @@ fts_get_rows_count( pars_info_bind_function(info, "my_func", fts_read_ulint, &count); fts_get_table_name(fts_table, table_name); - pars_info_bind_id(info, true, "table_name", table_name); + pars_info_bind_id(info, "table_name", table_name); graph = fts_parse_sql( fts_table, diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index d0513643230..392907eb956 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2020, MariaDB Corporation. +Copyright (c) 2016, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -492,7 +492,7 @@ fts_index_fetch_nodes( fts_get_table_name(fts_table, table_name); - pars_info_bind_id(info, true, "table_name", table_name); + pars_info_bind_id(info, "table_name", table_name); } pars_info_bind_function(info, "my_func", fetch->read_record, fetch); @@ -821,7 +821,7 @@ fts_index_fetch_words( info, "word", word->f_str, word->f_len); fts_get_table_name(&optim->fts_index_table, table_name); - pars_info_bind_id(info, true, "table_name", table_name); + pars_info_bind_id(info, "table_name", table_name); graph = fts_parse_sql( &optim->fts_index_table, @@ -977,7 +977,7 @@ fts_table_fetch_doc_ids( pars_info_bind_function(info, "my_func", fts_fetch_doc_ids, doc_ids); fts_get_table_name(fts_table, table_name); - pars_info_bind_id(info, true, "table_name", table_name); + pars_info_bind_id(info, "table_name", table_name); graph = fts_parse_sql( fts_table, @@ -1441,7 +1441,7 @@ fts_optimize_write_word( fts_table->suffix = fts_get_suffix(selected); fts_get_table_name(fts_table, table_name); - pars_info_bind_id(info, true, "table_name", table_name); + pars_info_bind_id(info, "table_name", table_name); graph = fts_parse_sql( fts_table, @@ -2033,11 +2033,11 @@ fts_optimize_purge_deleted_doc_ids( used in the fts_delete_doc_ids_sql */ optim->fts_common_table.suffix = fts_common_tables[3]; fts_get_table_name(&optim->fts_common_table, deleted); - pars_info_bind_id(info, true, fts_common_tables[3], deleted); + pars_info_bind_id(info, fts_common_tables[3], deleted); optim->fts_common_table.suffix = fts_common_tables[4]; fts_get_table_name(&optim->fts_common_table, deleted_cache); - pars_info_bind_id(info, true, fts_common_tables[4], deleted_cache); + pars_info_bind_id(info, fts_common_tables[4], deleted_cache); graph = fts_parse_sql(NULL, info, fts_delete_doc_ids_sql); @@ -2090,12 +2090,11 @@ fts_optimize_purge_deleted_doc_id_snapshot( used in the fts_end_delete_sql */ optim->fts_common_table.suffix = fts_common_tables[0]; fts_get_table_name(&optim->fts_common_table, being_deleted); - pars_info_bind_id(info, true, fts_common_tables[0], being_deleted); + pars_info_bind_id(info, fts_common_tables[0], being_deleted); optim->fts_common_table.suffix = fts_common_tables[1]; fts_get_table_name(&optim->fts_common_table, being_deleted_cache); - pars_info_bind_id(info, true, fts_common_tables[1], - being_deleted_cache); + pars_info_bind_id(info, fts_common_tables[1], being_deleted_cache); /* Delete the doc ids that were copied to delete pending state at the start of optimize. */ @@ -2151,20 +2150,19 @@ fts_optimize_create_deleted_doc_id_snapshot( used in the fts_init_delete_sql */ optim->fts_common_table.suffix = fts_common_tables[0]; fts_get_table_name(&optim->fts_common_table, being_deleted); - pars_info_bind_id(info, true, fts_common_tables[0], being_deleted); + pars_info_bind_id(info, fts_common_tables[0], being_deleted); optim->fts_common_table.suffix = fts_common_tables[3]; fts_get_table_name(&optim->fts_common_table, deleted); - pars_info_bind_id(info, true, fts_common_tables[3], deleted); + pars_info_bind_id(info, fts_common_tables[3], deleted); optim->fts_common_table.suffix = fts_common_tables[1]; fts_get_table_name(&optim->fts_common_table, being_deleted_cache); - pars_info_bind_id(info, true, fts_common_tables[1], - being_deleted_cache); + pars_info_bind_id(info, fts_common_tables[1], being_deleted_cache); optim->fts_common_table.suffix = fts_common_tables[4]; fts_get_table_name(&optim->fts_common_table, deleted_cache); - pars_info_bind_id(info, true, fts_common_tables[4], deleted_cache); + pars_info_bind_id(info, fts_common_tables[4], deleted_cache); /* Move doc_ids that are to be deleted to state being deleted. */ graph = fts_parse_sql(NULL, info, fts_init_delete_sql); diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc index 8f212ff6676..3c689d0c496 100644 --- a/storage/innobase/fts/fts0que.cc +++ b/storage/innobase/fts/fts0que.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2020, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -2146,7 +2146,7 @@ fts_query_find_term( query->fts_index_table.suffix = fts_get_suffix(selected); fts_get_table_name(&query->fts_index_table, table_name); - pars_info_bind_id(info, true, "index_table_name", table_name); + pars_info_bind_id(info, "index_table_name", table_name); } select.found = FALSE; @@ -2286,7 +2286,7 @@ fts_query_total_docs_containing_term( fts_get_table_name(&query->fts_index_table, table_name); - pars_info_bind_id(info, true, "index_table_name", table_name); + pars_info_bind_id(info, "index_table_name", table_name); graph = fts_parse_sql( &query->fts_index_table, @@ -2369,7 +2369,7 @@ fts_query_terms_in_document( fts_get_table_name(&query->fts_index_table, table_name); - pars_info_bind_id(info, true, "index_table_name", table_name); + pars_info_bind_id(info, "index_table_name", table_name); graph = fts_parse_sql( &query->fts_index_table, diff --git a/storage/innobase/fts/fts0sql.cc b/storage/innobase/fts/fts0sql.cc index edd3a13819e..09ec2d08324 100644 --- a/storage/innobase/fts/fts0sql.cc +++ b/storage/innobase/fts/fts0sql.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2019, MariaDB Corporation. +Copyright (c) 2019, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -248,7 +248,7 @@ fts_get_select_columns_str( sel_str = mem_heap_printf(heap, "sel%lu", (ulong) i); /* Set copy_name to TRUE since it's dynamic. */ - pars_info_bind_id(info, TRUE, sel_str, field->name); + pars_info_bind_id(info, sel_str, field->name); str = mem_heap_printf( heap, "%s%s$%s", str, (*str) ? ", " : "", sel_str); diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 6984f405221..42b6a34188c 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2014, 2020, MariaDB Corporation. +Copyright (c) 2014, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -3435,7 +3435,7 @@ i_s_fts_index_table_fill_selected( FTS_INIT_INDEX_TABLE(&fts_table, fts_get_suffix(selected), FTS_INDEX_TABLE, index); fts_get_table_name(&fts_table, table_name); - pars_info_bind_id(info, true, "table_name", table_name); + pars_info_bind_id(info, "table_name", table_name); graph = fts_parse_sql( &fts_table, info, diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index fe845005536..54aea9d2d3d 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -2,7 +2,7 @@ Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2014, 2019, MariaDB Corporation. +Copyright (c) 2014, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -754,13 +754,14 @@ btr_validate_index( @param[in,out] page page to remove @param[in] index index tree @param[in,out] mtr mini-transaction */ -void +dberr_t btr_level_list_remove_func( ulint space, ulint zip_size, page_t* page, dict_index_t* index, - mtr_t* mtr); + mtr_t* mtr) + MY_ATTRIBUTE((warn_unused_result)); /*************************************************************//** Removes a page from the level list of pages. diff --git a/storage/innobase/include/fil0pagecompress.h b/storage/innobase/include/fil0pagecompress.h index 9baf3289380..c513a94c799 100644 --- a/storage/innobase/include/fil0pagecompress.h +++ b/storage/innobase/include/fil0pagecompress.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (C) 2013, 2019 MariaDB Corporation. +Copyright (C) 2013, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -49,7 +49,7 @@ ulint fil_page_compress( /** Decompress a page that may be subject to page_compressed compression. @param[in,out] tmp_buf temporary buffer (of innodb_page_size) @param[in,out] buf compressed page buffer -@param[in] flags talespace flags +@param[in] flags tablespace flags @return size of the compressed data @retval 0 if decompression failed @retval srv_page_size if the page was not compressed */ diff --git a/storage/innobase/include/pars0pars.h b/storage/innobase/include/pars0pars.h index 73a19dd24d8..475dd523d38 100644 --- a/storage/innobase/include/pars0pars.h +++ b/storage/innobase/include/pars0pars.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -491,7 +491,6 @@ void pars_info_bind_id( /*=============*/ pars_info_t* info, /*!< in: info struct */ - ibool copy_name,/* in: make a copy of name if TRUE */ const char* name, /*!< in: name */ const char* id); /*!< in: id */ /****************************************************************//** @@ -538,15 +537,6 @@ pars_info_bind_ull_literal( MY_ATTRIBUTE((nonnull)); /****************************************************************//** -Add bound id. */ -void -pars_info_add_id( -/*=============*/ - pars_info_t* info, /*!< in: info struct */ - const char* name, /*!< in: name */ - const char* id); /*!< in: id */ - -/****************************************************************//** Get bound literal with the given name. @return bound literal, or NULL if not found */ pars_bound_lit_t* diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index f08788b7748..9949ebded8e 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -5797,7 +5797,8 @@ lock_sec_rec_read_check_and_lock( if (!page_rec_is_supremum(rec) && page_get_max_trx_id(block->frame) >= trx_sys.get_min_trx_id() && lock_rec_convert_impl_to_expl(thr_get_trx(thr), block, rec, - index, offsets)) { + index, offsets) + && gap_mode == LOCK_REC_NOT_GAP) { /* We already hold an implicit exclusive lock. */ return DB_SUCCESS; } @@ -5879,7 +5880,8 @@ lock_clust_rec_read_check_and_lock( if (heap_no != PAGE_HEAP_NO_SUPREMUM && lock_rec_convert_impl_to_expl(thr_get_trx(thr), block, rec, - index, offsets)) { + index, offsets) + && gap_mode == LOCK_REC_NOT_GAP) { /* We already hold an implicit exclusive lock. */ return DB_SUCCESS; } diff --git a/storage/innobase/pars/pars0pars.cc b/storage/innobase/pars/pars0pars.cc index a27411c3d8b..9f1aae9aa07 100644 --- a/storage/innobase/pars/pars0pars.cc +++ b/storage/innobase/pars/pars0pars.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2018, 2019, MariaDB Corporation. +Copyright (c) 2018, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -2356,7 +2356,6 @@ void pars_info_bind_id( /*==============*/ pars_info_t* info, /*!< in: info struct */ - ibool copy_name, /* in: copy name if TRUE */ const char* name, /*!< in: name */ const char* id) /*!< in: id */ { @@ -2379,8 +2378,7 @@ pars_info_bind_id( bid = static_cast<pars_bound_id_t*>( ib_vector_push(info->bound_ids, NULL)); - bid->name = (copy_name) - ? mem_heap_strdup(info->heap, name) : name; + bid->name = name; } bid->id = id; diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 59d9272fda6..0585ac08542 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -225,6 +225,19 @@ struct row_import { found and was readable */ }; +struct fil_iterator_t { + pfs_os_file_t file; /*!< File handle */ + const char* filepath; /*!< File path name */ + os_offset_t start; /*!< From where to start */ + os_offset_t end; /*!< Where to stop */ + os_offset_t file_size; /*!< File size in bytes */ + ulint n_io_buffers; /*!< Number of pages to use + for IO */ + byte* io_buffer; /*!< Buffer to use for IO */ + fil_space_crypt_t *crypt_data; /*!< Crypt data (if encrypted) */ + byte* crypt_io_buffer; /*!< IO buffer when encrypted */ +}; + /** Use the page cursor to iterate over records in a block. */ class RecIterator { public: @@ -438,6 +451,10 @@ public: ? block->page.zip.data : block->frame; } + /** Invoke the functionality for the callback */ + virtual dberr_t run(const fil_iterator_t& iter, + buf_block_t* block) UNIV_NOTHROW = 0; + protected: /** Get the physical offset of the extent descriptor within the page. @param page_no page number of the extent descriptor @@ -598,6 +615,24 @@ AbstractCallback::init( } /** +TODO: This can be made parallel trivially by chunking up the file +and creating a callback per thread.. Main benefit will be to use +multiple CPUs for checksums and compressed tables. We have to do +compressed tables block by block right now. Secondly we need to +decompress/compress and copy too much of data. These are +CPU intensive. + +Iterate over all the pages in the tablespace. +@param iter - Tablespace iterator +@param block - block to use for IO +@param callback - Callback to inspect and update page contents +@retval DB_SUCCESS or error code */ +static dberr_t fil_iterate( + const fil_iterator_t& iter, + buf_block_t* block, + AbstractCallback& callback); + +/** Try and determine the index root pages by checking if the next/prev pointers are both FIL_NULL. We need to ensure that skip deleted pages. */ struct FetchIndexRootPages : public AbstractCallback { @@ -614,19 +649,24 @@ struct FetchIndexRootPages : public AbstractCallback { ulint m_page_no; /*!< Root page number */ }; - typedef std::vector<Index, ut_allocator<Index> > Indexes; - /** Constructor @param trx covering (user) transaction @param table table definition in server .*/ FetchIndexRootPages(const dict_table_t* table, trx_t* trx) : AbstractCallback(trx, ULINT_UNDEFINED), - m_table(table) UNIV_NOTHROW { } + m_table(table), m_index(0, 0) UNIV_NOTHROW { } /** Destructor */ ~FetchIndexRootPages() UNIV_NOTHROW override { } + /** Fetch the clustered index root page in the tablespace + @param iter Tablespace iterator + @param block Block to use for IO + @retval DB_SUCCESS or error code */ + dberr_t run(const fil_iterator_t& iter, + buf_block_t* block) UNIV_NOTHROW; + /** Called for each block as it is read from the file. @param block block to convert, it is not from the buffer pool. @retval DB_SUCCESS or error code. */ @@ -640,7 +680,7 @@ struct FetchIndexRootPages : public AbstractCallback { const dict_table_t* m_table; /** Index information */ - Indexes m_indexes; + Index m_index; }; /** Called for each block as it is read from the file. Check index pages to @@ -655,39 +695,27 @@ dberr_t FetchIndexRootPages::operator()(buf_block_t* block) UNIV_NOTHROW const page_t* page = get_frame(block); - ulint page_type = fil_page_get_type(page); - - if (page_type == FIL_PAGE_TYPE_XDES) { - return set_current_xdes(block->page.id.page_no(), page); - } else if (fil_page_index_page_check(page) - && !is_free(block->page.id.page_no()) - && !page_has_siblings(page)) { - - index_id_t id = btr_page_get_index_id(page); - - m_indexes.push_back(Index(id, block->page.id.page_no())); + m_index.m_id = btr_page_get_index_id(page); + m_index.m_page_no = block->page.id.page_no(); - if (m_indexes.size() == 1) { - /* Check that the tablespace flags match the table flags. */ - ulint expected = dict_tf_to_fsp_flags(m_table->flags); - if (!fsp_flags_match(expected, m_space_flags)) { - ib_errf(m_trx->mysql_thd, IB_LOG_LEVEL_ERROR, - ER_TABLE_SCHEMA_MISMATCH, - "Expected FSP_SPACE_FLAGS=0x%x, .ibd " - "file contains 0x%x.", - unsigned(expected), - unsigned(m_space_flags)); - return(DB_CORRUPTION); - } - } + /* Check that the tablespace flags match the table flags. */ + ulint expected = dict_tf_to_fsp_flags(m_table->flags); + if (!fsp_flags_match(expected, m_space_flags)) { + ib_errf(m_trx->mysql_thd, IB_LOG_LEVEL_ERROR, + ER_TABLE_SCHEMA_MISMATCH, + "Expected FSP_SPACE_FLAGS=0x%x, .ibd " + "file contains 0x%x.", + unsigned(expected), + unsigned(m_space_flags)); + return(DB_CORRUPTION); + } - if (!page_is_comp(block->frame) != - !dict_table_is_comp(m_table)) { - ib_errf(m_trx->mysql_thd, IB_LOG_LEVEL_ERROR, - ER_TABLE_SCHEMA_MISMATCH, - "ROW_FORMAT mismatch"); - return DB_CORRUPTION; - } + if (!page_is_comp(block->frame) != + !dict_table_is_comp(m_table)) { + ib_errf(m_trx->mysql_thd, IB_LOG_LEVEL_ERROR, + ER_TABLE_SCHEMA_MISMATCH, + "ROW_FORMAT mismatch"); + return DB_CORRUPTION; } return DB_SUCCESS; @@ -699,11 +727,9 @@ Update the import configuration that will be used to import the tablespace. dberr_t FetchIndexRootPages::build_row_import(row_import* cfg) const UNIV_NOTHROW { - Indexes::const_iterator end = m_indexes.end(); - ut_a(cfg->m_table == m_table); cfg->m_zip_size = m_zip_size; - cfg->m_n_indexes = m_indexes.size(); + cfg->m_n_indexes = 1; if (cfg->m_n_indexes == 0) { @@ -729,37 +755,32 @@ FetchIndexRootPages::build_row_import(row_import* cfg) const UNIV_NOTHROW row_index_t* cfg_index = cfg->m_indexes; - for (Indexes::const_iterator it = m_indexes.begin(); - it != end; - ++it, ++cfg_index) { + char name[BUFSIZ]; - char name[BUFSIZ]; + snprintf(name, sizeof(name), "index" IB_ID_FMT, m_index.m_id); - snprintf(name, sizeof(name), "index" IB_ID_FMT, it->m_id); + ulint len = strlen(name) + 1; - ulint len = strlen(name) + 1; + cfg_index->m_name = UT_NEW_ARRAY_NOKEY(byte, len); - cfg_index->m_name = UT_NEW_ARRAY_NOKEY(byte, len); - - /* Trigger OOM */ - DBUG_EXECUTE_IF( - "ib_import_OOM_12", - UT_DELETE_ARRAY(cfg_index->m_name); - cfg_index->m_name = NULL; - ); + /* Trigger OOM */ + DBUG_EXECUTE_IF( + "ib_import_OOM_12", + UT_DELETE_ARRAY(cfg_index->m_name); + cfg_index->m_name = NULL; + ); - if (cfg_index->m_name == NULL) { - return(DB_OUT_OF_MEMORY); - } + if (cfg_index->m_name == NULL) { + return(DB_OUT_OF_MEMORY); + } - memcpy(cfg_index->m_name, name, len); + memcpy(cfg_index->m_name, name, len); - cfg_index->m_id = it->m_id; + cfg_index->m_id = m_index.m_id; - cfg_index->m_space = m_space; + cfg_index->m_space = m_space; - cfg_index->m_page_no = it->m_page_no; - } + cfg_index->m_page_no = m_index.m_page_no; return(DB_SUCCESS); } @@ -818,6 +839,11 @@ public: } } + dberr_t run(const fil_iterator_t& iter, buf_block_t* block) UNIV_NOTHROW + { + return fil_iterate(iter, block, *this); + } + /** Called for each block as it is read from the file. @param block block to convert, it is not from the buffer pool. @retval DB_SUCCESS or error code. */ @@ -1874,10 +1900,13 @@ PageConverter::update_index_page( if (is_free(block->page.id.page_no())) { return(DB_SUCCESS); } else if ((id = btr_page_get_index_id(page)) != m_index->m_id) { - row_index_t* index = find_index(id); if (UNIV_UNLIKELY(!index)) { + if (m_cfg->m_missing) { + return DB_SUCCESS; + } + ib::error() << "Page for tablespace " << m_space << " is index page with id " << id << " but that index is not found from" @@ -3347,20 +3376,6 @@ dberr_t row_import_update_discarded_flag(trx_t* trx, table_id_t table_id, return(err); } -struct fil_iterator_t { - pfs_os_file_t file; /*!< File handle */ - const char* filepath; /*!< File path name */ - os_offset_t start; /*!< From where to start */ - os_offset_t end; /*!< Where to stop */ - os_offset_t file_size; /*!< File size in bytes */ - ulint n_io_buffers; /*!< Number of pages to use - for IO */ - byte* io_buffer; /*!< Buffer to use for IO */ - fil_space_crypt_t *crypt_data; /*!< Crypt data (if encrypted) */ - byte* crypt_io_buffer; /*!< IO buffer when encrypted */ -}; - - /** InnoDB writes page by page when there is page compressed tablespace involved. It does help to save the disk space when punch hole is enabled @@ -3420,22 +3435,92 @@ dberr_t fil_import_compress_fwrite(const fil_iterator_t &iter, return DB_SUCCESS; } -/********************************************************************//** -TODO: This can be made parallel trivially by chunking up the file and creating -a callback per thread. . Main benefit will be to use multiple CPUs for -checksums and compressed tables. We have to do compressed tables block by -block right now. Secondly we need to decompress/compress and copy too much -of data. These are CPU intensive. +dberr_t FetchIndexRootPages::run(const fil_iterator_t& iter, + buf_block_t* block) UNIV_NOTHROW +{ + const unsigned zip_size= fil_space_t::zip_size(m_space_flags); + const unsigned size= zip_size ? zip_size : unsigned(srv_page_size); + const ulint buf_size= +#ifdef HAVE_LZO + LZO1X_1_15_MEM_COMPRESS+ +#elif defined HAVE_SNAPPY + snappy_max_compressed_length(srv_page_size) + +#endif + srv_page_size; + byte* page_compress_buf = static_cast<byte*>(malloc(buf_size)); + ut_ad(!srv_read_only_mode); -Iterate over all the pages in the tablespace. -@param iter - Tablespace iterator -@param block - block to use for IO -@param callback - Callback to inspect and update page contents -@retval DB_SUCCESS or error code */ -static -dberr_t -fil_iterate( -/*========*/ + if (!page_compress_buf) + return DB_OUT_OF_MEMORY; + + const bool encrypted= iter.crypt_data != NULL && + iter.crypt_data->should_encrypt(); + byte* const readptr= iter.io_buffer; + block->frame= readptr; + + if (block->page.zip.data) + block->page.zip.data= readptr; + + IORequest read_request(IORequest::READ); + read_request.disable_partial_io_warnings(); + ulint page_no= 0; + bool page_compressed= false; + + dberr_t err= os_file_read_no_error_handling( + read_request, iter.file, readptr, 3 * size, size, 0); + if (err != DB_SUCCESS) + { + ib::error() << iter.filepath << ": os_file_read() failed"; + goto func_exit; + } + + block->page.id.set_page_no(3); + page_no= page_get_page_no(readptr); + + if (page_no != 3) + { +page_corrupted: + ib::warn() << filename() << ": Page 3 at offset " + << 3 * size << " looks corrupted."; + err= DB_CORRUPTION; + goto func_exit; + } + + page_compressed= fil_page_is_compressed_encrypted(readptr) || + fil_page_is_compressed(readptr); + + if (page_compressed && block->page.zip.data) + goto page_corrupted; + + if (encrypted) + { + if (!fil_space_verify_crypt_checksum(readptr, zip_size)) + goto page_corrupted; + + if (!fil_space_decrypt(get_space_id(), iter.crypt_data, readptr, + size, m_space_flags, readptr, &err) || + err != DB_SUCCESS) + goto func_exit; + } + + if (page_compressed) + { + ulint compress_length= fil_page_decompress(page_compress_buf, readptr, + m_space_flags); + ut_ad(compress_length != srv_page_size); + if (compress_length == 0) + goto page_corrupted; + } + else if (buf_page_is_corrupted(false, readptr, m_space_flags)) + goto page_corrupted; + + err= this->operator()(block); +func_exit: + free(page_compress_buf); + return err; +} + +static dberr_t fil_iterate( const fil_iterator_t& iter, buf_block_t* block, AbstractCallback& callback) @@ -3911,7 +3996,7 @@ fil_tablespace_iterate( block->page.zip.data = block->frame + srv_page_size; } - err = fil_iterate(iter, block, callback); + err = callback.run(iter, block); if (iter.crypt_data) { fil_space_destroy_crypt_data(&iter.crypt_data); @@ -4056,6 +4141,16 @@ row_import_for_mysql( cfg.m_zip_size = 0; + if (UT_LIST_GET_LEN(table->indexes) > 1) { + ib_errf(trx->mysql_thd, IB_LOG_LEVEL_ERROR, + ER_INTERNAL_ERROR, + "Drop all secondary indexes before importing " + "table %s when .cfg file is missing.", + table->name.m_name); + err = DB_ERROR; + return row_import_error(prebuilt, trx, err); + } + FetchIndexRootPages fetchIndexRootPages(table, trx); err = fil_tablespace_iterate( diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 6f7b9dde3e1..c191b972cd0 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1666,23 +1666,6 @@ row_ins_check_foreign_constraint( cmp = cmp_dtuple_rec(entry, rec, offsets); if (cmp == 0) { - if (check_table->versioned()) { - bool history_row = false; - - if (check_index->is_primary()) { - history_row = check_index-> - vers_history_row(rec, offsets); - } else if (check_index-> - vers_history_row(rec, history_row)) - { - break; - } - - if (history_row) { - continue; - } - } - if (rec_get_deleted_flag(rec, rec_offs_comp(offsets))) { /* In delete-marked records, DB_TRX_ID must @@ -1704,6 +1687,23 @@ row_ins_check_foreign_constraint( goto end_scan; } } else { + if (check_table->versioned()) { + bool history_row = false; + + if (check_index->is_primary()) { + history_row = check_index-> + vers_history_row(rec, + offsets); + } else if (check_index-> + vers_history_row(rec, + history_row)) { + break; + } + + if (history_row) { + continue; + } + } /* Found a matching record. Lock only a record because we can allow inserts into gaps */ diff --git a/storage/perfschema/CMakeLists.txt b/storage/perfschema/CMakeLists.txt index 56083f24223..7ed365ea175 100644 --- a/storage/perfschema/CMakeLists.txt +++ b/storage/perfschema/CMakeLists.txt @@ -187,9 +187,10 @@ table_session_connect_attrs.cc table_session_account_connect_attrs.cc ) -MYSQL_ADD_PLUGIN(perfschema ${PERFSCHEMA_SOURCES} STORAGE_ENGINE DEFAULT STATIC_ONLY) +MYSQL_ADD_PLUGIN(perfschema ${PERFSCHEMA_SOURCES} STORAGE_ENGINE DEFAULT + STATIC_ONLY DEPENDS GenServerSource) + IF (TARGET perfschema) - ADD_DEPENDENCIES(perfschema GenServerSource) IF(WITH_UNIT_TESTS) ADD_SUBDIRECTORY(unittest) ENDIF(WITH_UNIT_TESTS) diff --git a/storage/spider/mysql-test/spider/bugfix/include/mdev_24523_deinit.inc b/storage/spider/mysql-test/spider/bugfix/include/mdev_24523_deinit.inc new file mode 100644 index 00000000000..e8d30523978 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/mdev_24523_deinit.inc @@ -0,0 +1,9 @@ +--let $MASTER_1_COMMENT_P_2_1= $MASTER_1_COMMENT_P_2_1_BACKUP +--let $CHILD2_1_CREATE_TABLES= $CHILD2_1_CREATE_TABLES_BACKUP +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_deinit.inc +--enable_result_log +--enable_query_log +--enable_warnings diff --git a/storage/spider/mysql-test/spider/bugfix/include/mdev_24523_init.inc b/storage/spider/mysql-test/spider/bugfix/include/mdev_24523_init.inc new file mode 100644 index 00000000000..989faa54c16 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/mdev_24523_init.inc @@ -0,0 +1,31 @@ +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_init.inc +--enable_result_log +--enable_query_log +--enable_warnings +--let $MASTER_1_COMMENT_P_2_1_BACKUP= $MASTER_1_COMMENT_P_2_1 +let $MASTER_1_COMMENT_P_2_1= + PARTITION BY RANGE(i) ( + PARTITION pt1 VALUES LESS THAN (5) COMMENT='srv "s_2_1", table "ta_r2"', + PARTITION pt2 VALUES LESS THAN (10) COMMENT='srv "s_2_1", table "ta_r3"', + PARTITION pt3 VALUES LESS THAN MAXVALUE COMMENT='srv "s_2_1", table "ta_r4"' + ); +--let $CHILD2_1_CREATE_TABLES_BACKUP= $CHILD2_1_CREATE_TABLES +let $CHILD2_1_CREATE_TABLES= + CREATE TABLE ta_r2 ( + i INT, + j JSON, + PRIMARY KEY(i) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET $STR_SEMICOLON + CREATE TABLE ta_r3 ( + i INT, + j JSON, + PRIMARY KEY(i) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET $STR_SEMICOLON + CREATE TABLE ta_r4 ( + i INT, + j JSON, + PRIMARY KEY(i) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET; diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_24523.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_24523.result new file mode 100644 index 00000000000..0b3d6c3142b --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_24523.result @@ -0,0 +1,58 @@ +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 + +this test is for MDEV-24523 + +drop and create databases +connection master_1; +CREATE DATABASE auto_test_local; +USE auto_test_local; +connection child2_1; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; + +create table and insert +connection child2_1; +CHILD2_1_CREATE_TABLES +connection master_1; +CREATE TABLE tbl_a ( +i INT, +j JSON, +PRIMARY KEY(i) +) ENGINE=Spider PARTITION BY RANGE(i) ( +PARTITION pt1 VALUES LESS THAN (5) COMMENT='srv "s_2_1", table "ta_r2"', +PARTITION pt2 VALUES LESS THAN (10) COMMENT='srv "s_2_1", table "ta_r3"', +PARTITION pt3 VALUES LESS THAN MAXVALUE COMMENT='srv "s_2_1", table "ta_r4"' + ) +INSERT INTO tbl_a VALUES (1, '{ "a": 1, "b": [2, 3]}'); + +test 1 +connection master_1; +UPDATE tbl_a SET j = JSON_REPLACE(j, '$.a', 10, '$.c', '[1, 2]'); +SELECT * FROM tbl_a; +i j +1 {"a": 10, "b": [2, 3]} +TRUNCATE TABLE tbl_a; +INSERT INTO tbl_a VALUES (1, '{ "a": 1, "b": [2, 3]}'); +UPDATE tbl_a SET j = JSON_REPLACE(j, '$.a', 10, '$.b', '[1, 2]'); +SELECT * FROM tbl_a; +i j +1 {"a": 10, "b": "[1, 2]"} + +deinit +connection master_1; +DROP DATABASE IF EXISTS auto_test_local; +connection child2_1; +DROP DATABASE IF EXISTS auto_test_remote; +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 + +end of test diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_24523.cnf b/storage/spider/mysql-test/spider/bugfix/t/mdev_24523.cnf new file mode 100644 index 00000000000..05dfd8a0bce --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_24523.cnf @@ -0,0 +1,3 @@ +!include include/default_mysqld.cnf +!include ../my_1_1.cnf +!include ../my_2_1.cnf diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_24523.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_24523.test new file mode 100644 index 00000000000..00c0c873f20 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_24523.test @@ -0,0 +1,66 @@ +--source ../include/mdev_24523_init.inc +--echo +--echo this test is for MDEV-24523 +--echo +--echo drop and create databases + +--connection master_1 +--disable_warnings +CREATE DATABASE auto_test_local; +USE auto_test_local; + +--connection child2_1 +CREATE DATABASE auto_test_remote; +USE auto_test_remote; +--enable_warnings + +--echo +--echo create table and insert + +--connection child2_1 +--disable_query_log +--disable_ps_protocol +echo CHILD2_1_CREATE_TABLES; +eval $CHILD2_1_CREATE_TABLES; +--enable_ps_protocol +--enable_query_log + +--connection master_1 +--disable_query_log +echo CREATE TABLE tbl_a ( + i INT, + j JSON, + PRIMARY KEY(i) +) $MASTER_1_ENGINE $MASTER_1_COMMENT_P_2_1; +eval CREATE TABLE tbl_a ( + i INT, + j JSON, + PRIMARY KEY(i) +) $MASTER_1_ENGINE $MASTER_1_COMMENT_P_2_1; +--enable_query_log +INSERT INTO tbl_a VALUES (1, '{ "a": 1, "b": [2, 3]}'); + +--echo +--echo test 1 + +--connection master_1 +UPDATE tbl_a SET j = JSON_REPLACE(j, '$.a', 10, '$.c', '[1, 2]'); +SELECT * FROM tbl_a; +TRUNCATE TABLE tbl_a; +INSERT INTO tbl_a VALUES (1, '{ "a": 1, "b": [2, 3]}'); +UPDATE tbl_a SET j = JSON_REPLACE(j, '$.a', 10, '$.b', '[1, 2]'); +SELECT * FROM tbl_a; +--echo +--echo deinit +--disable_warnings + +--connection master_1 +DROP DATABASE IF EXISTS auto_test_local; + +--connection child2_1 +DROP DATABASE IF EXISTS auto_test_remote; + +--enable_warnings +--source ../include/mdev_24523_deinit.inc +--echo +--echo end of test diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 78656850e48..8ebe0a4c2a8 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -18209,9 +18209,9 @@ static void test_bug40365(void) if (!opt_silent) fprintf(stdout, "\ntime[%d]: %02d-%02d-%02d ", i, tm[i].year, tm[i].month, tm[i].day); - DIE_UNLESS(tm[i].year == 0); - DIE_UNLESS(tm[i].month == 0); - DIE_UNLESS(tm[i].day == 0); + DIE_UNLESS(tm[i].year == 0); + DIE_UNLESS(tm[i].month == 0); + DIE_UNLESS(tm[i].day == 0); } mysql_stmt_close(stmt); rc= mysql_commit(mysql); |