diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2021-10-21 13:41:04 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2021-10-21 13:41:04 +0300 |
commit | e4a7c15dd6ba812ac9a4183dec937513eb68a2bc (patch) | |
tree | 41954d8a6608a2309994d3bbe09f72c1cc73ce6f | |
parent | 1388845e048011932a6d715936a781479c5e6af3 (diff) | |
parent | 1a2308d3f443d8fcacf5506cb96f802dee3a3519 (diff) | |
download | mariadb-git-e4a7c15dd6ba812ac9a4183dec937513eb68a2bc.tar.gz |
Merge 10.2 into 10.3
70 files changed, 1944 insertions, 524 deletions
diff --git a/libmariadb b/libmariadb -Subproject b99172386a740ef0c8136e9a6cd7d9ad9a77b31 +Subproject 735a7299dbae19cc2b82b9697becaf90e9b4304 diff --git a/mysql-test/main/ctype_utf16le.result b/mysql-test/main/ctype_utf16le.result index a43ed6ee538..e95b056719d 100644 --- a/mysql-test/main/ctype_utf16le.result +++ b/mysql-test/main/ctype_utf16le.result @@ -3000,5 +3000,38 @@ DROP TABLE t1; # SET STORAGE_ENGINE=Default; # +# MDEV-23408 Wrong result upon query from I_S and further Assertion `!alias_arg || strlen(alias_arg->str) == alias_arg->length' failed with certain connection charset +# +SET NAMES utf8; +SET SESSION character_set_connection= utf16le; +CREATE TABLE kv (v TEXT CHARACTER SET latin1); +CREATE TABLE t (a INT); +CREATE VIEW v AS SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; +LOAD DATA INFILE 'MYSQLD_DATADIR/test/v.frm' REPLACE INTO TABLE kv CHARACTER SET latin1; +SELECT LOWER(v) FROM kv WHERE v LIKE _binary'query=%'; +LOWER(v) +query=select `information_schema`.`tables`.`table_catalog` as `table_catalog`,`information_schema`.`tables`.`table_schema` as `table_schema`,`information_schema`.`tables`.`table_name` as `table_name`,`information_schema`.`tables`.`table_type` as `table_type`,`information_schema`.`tables`.`engine` as `engine`,`information_schema`.`tables`.`version` as `version`,`information_schema`.`tables`.`row_format` as `row_format`,`information_schema`.`tables`.`table_rows` as `table_rows`,`information_schema`.`tables`.`avg_row_length` as `avg_row_length`,`information_schema`.`tables`.`data_length` as `data_length`,`information_schema`.`tables`.`max_data_length` as `max_data_length`,`information_schema`.`tables`.`index_length` as `index_length`,`information_schema`.`tables`.`data_free` as `data_free`,`information_schema`.`tables`.`auto_increment` as `auto_increment`,`information_schema`.`tables`.`create_time` as `create_time`,`information_schema`.`tables`.`update_time` as `update_time`,`information_schema`.`tables`.`check_time` as `check_time`,`information_schema`.`tables`.`table_collation` as `table_collation`,`information_schema`.`tables`.`checksum` as `checksum`,`information_schema`.`tables`.`create_options` as `create_options`,`information_schema`.`tables`.`table_comment` as `table_comment`,`information_schema`.`tables`.`max_index_length` as `max_index_length`,`information_schema`.`tables`.`temporary` as `temporary` from `information_schema`.`tables` where `information_schema`.`tables`.`table_name` = 't1' +TRUNCATE TABLE kv; +SELECT * FROM v; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ENGINE VERSION ROW_FORMAT TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE AUTO_INCREMENT CREATE_TIME UPDATE_TIME CHECK_TIME TABLE_COLLATION CHECKSUM CREATE_OPTIONS TABLE_COMMENT MAX_INDEX_LENGTH TEMPORARY +LOCK TABLE t WRITE; +UNLOCK TABLES; +DROP VIEW v; +DROP TABLE t; +DROP TABLE kv; +CREATE TABLE t (a INT); +SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=CONCAT('t',0x00,'1'); +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ENGINE VERSION ROW_FORMAT TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE AUTO_INCREMENT CREATE_TIME UPDATE_TIME CHECK_TIME TABLE_COLLATION CHECKSUM CREATE_OPTIONS TABLE_COMMENT MAX_INDEX_LENGTH TEMPORARY +LOCK TABLE t WRITE; +UNLOCK TABLES; +DROP TABLE t; +CREATE TABLE t (a INT); +SELECT TABLE_NAME, HEX(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=CONCAT('t',0x00,'1'); +TABLE_NAME HEX(TABLE_NAME) +SELECT TABLE_NAME, TABLE_SCHEMA, HEX(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=CONCAT('test',0x00,'1'); +TABLE_NAME TABLE_SCHEMA HEX(TABLE_NAME) +DROP TABLE t; +SET NAMES utf8; +# # End of 10.2 tests # diff --git a/mysql-test/main/ctype_utf16le.test b/mysql-test/main/ctype_utf16le.test index 204df136274..c0cac7f5d67 100644 --- a/mysql-test/main/ctype_utf16le.test +++ b/mysql-test/main/ctype_utf16le.test @@ -3,6 +3,7 @@ -- source include/have_utf32.inc -- source include/have_utf8mb4.inc +let $MYSQLD_DATADIR= `select @@datadir`; SET TIME_ZONE='+03:00'; @@ -811,5 +812,41 @@ let $coll_pad='utf16le_bin'; --source include/ctype_pad_all_engines.inc --echo # +--echo # MDEV-23408 Wrong result upon query from I_S and further Assertion `!alias_arg || strlen(alias_arg->str) == alias_arg->length' failed with certain connection charset +--echo # + + + +SET NAMES utf8; +SET SESSION character_set_connection= utf16le; + +CREATE TABLE kv (v TEXT CHARACTER SET latin1); +CREATE TABLE t (a INT); +CREATE VIEW v AS SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA INFILE '$MYSQLD_DATADIR/test/v.frm' REPLACE INTO TABLE kv CHARACTER SET latin1; +SELECT LOWER(v) FROM kv WHERE v LIKE _binary'query=%'; +TRUNCATE TABLE kv; +SELECT * FROM v; +LOCK TABLE t WRITE; +UNLOCK TABLES; +DROP VIEW v; +DROP TABLE t; +DROP TABLE kv; + +CREATE TABLE t (a INT); +SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=CONCAT('t',0x00,'1'); +LOCK TABLE t WRITE; +UNLOCK TABLES; +DROP TABLE t; + +CREATE TABLE t (a INT); +SELECT TABLE_NAME, HEX(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=CONCAT('t',0x00,'1'); +SELECT TABLE_NAME, TABLE_SCHEMA, HEX(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=CONCAT('test',0x00,'1'); +DROP TABLE t; + +SET NAMES utf8; + +--echo # --echo # End of 10.2 tests --echo # diff --git a/mysql-test/main/ctype_utf8.result b/mysql-test/main/ctype_utf8.result index f454e5e6052..d643ccc0082 100644 --- a/mysql-test/main/ctype_utf8.result +++ b/mysql-test/main/ctype_utf8.result @@ -11239,6 +11239,23 @@ DROP TABLE t1; # SET STORAGE_ENGINE=Default; # +# MDEV-23408 Wrong result upon query from I_S and further Assertion `!alias_arg || strlen(alias_arg->str) == alias_arg->length' failed with certain connection charset +# +SET NAMES utf8; +SET SESSION character_set_connection=latin1; +CREATE VIEW v1 AS SELECT 'ä' AS c1; +SELECT c1, HEX(c1) FROM v1; +c1 HEX(c1) +ä E4 +CREATE TABLE kv (v BLOB); +LOAD DATA INFILE 'MYSQLD_DATADIR/test/v1.frm' REPLACE INTO TABLE kv; +SELECT * FROM kv WHERE v LIKE _binary'query=%'; +v +query=select 'ä' AS `c1` +DROP TABLE kv; +DROP VIEW v1; +SET NAMES utf8; +# # End of 10.2 tests # # diff --git a/mysql-test/main/ctype_utf8.test b/mysql-test/main/ctype_utf8.test index 38dd9341e47..2e1f1e230f1 100644 --- a/mysql-test/main/ctype_utf8.test +++ b/mysql-test/main/ctype_utf8.test @@ -2,6 +2,8 @@ # Tests with the utf8 character set # +let $MYSQLD_DATADIR= `select @@datadir`; + let collation=utf8_unicode_ci; --source include/have_collation.inc SET TIME_ZONE='+03:00'; @@ -2166,6 +2168,22 @@ let $coll_pad='utf8_bin'; --source include/ctype_pad_all_engines.inc --echo # +--echo # MDEV-23408 Wrong result upon query from I_S and further Assertion `!alias_arg || strlen(alias_arg->str) == alias_arg->length' failed with certain connection charset +--echo # + +SET NAMES utf8; +SET SESSION character_set_connection=latin1; +CREATE VIEW v1 AS SELECT 'ä' AS c1; +SELECT c1, HEX(c1) FROM v1; +CREATE TABLE kv (v BLOB); +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA INFILE '$MYSQLD_DATADIR/test/v1.frm' REPLACE INTO TABLE kv; +SELECT * FROM kv WHERE v LIKE _binary'query=%'; +DROP TABLE kv; +DROP VIEW v1; +SET NAMES utf8; + +--echo # --echo # End of 10.2 tests --echo # diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index 94c3a0d6c0c..6656e0d5e51 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -934,6 +934,12 @@ CAST(JSON_EXTRACT('{"x":false}', '$.x') AS DECIMAL) AS cd; cf cd 0 0 # +# MDEV-24585 Assertion `je->s.cs == nice_js->charset()' failed in json_nice. +# +SELECT JSON_REPLACE( JSON_DETAILED('["x"]'), '$.a', 'xx' ); +JSON_REPLACE( JSON_DETAILED('["x"]'), '$.a', 'xx' ) +["x"] +# # End of 10.2 tests # # diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index a246113d210..24f2ae9267c 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -552,6 +552,12 @@ SELECT --echo # +--echo # MDEV-24585 Assertion `je->s.cs == nice_js->charset()' failed in json_nice. +--echo # + +SELECT JSON_REPLACE( JSON_DETAILED('["x"]'), '$.a', 'xx' ); + +--echo # --echo # End of 10.2 tests --echo # diff --git a/mysql-test/main/information_schema.result b/mysql-test/main/information_schema.result index 0559c42350d..45ef0799edc 100644 --- a/mysql-test/main/information_schema.result +++ b/mysql-test/main/information_schema.result @@ -2225,6 +2225,26 @@ SELECT * FROM v LIMIT ROWS EXAMINED 9; ERROR HY000: Sort aborted: DROP VIEW v; # +# MDEV-23408 Wrong result upon query from I_S and further Assertion `!alias_arg || strlen(alias_arg->str) == alias_arg->length' failed with certain connection charset +# +CREATE TABLE t (a INT); +SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=CONCAT('t',0x00,'1'); +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ENGINE VERSION ROW_FORMAT TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE AUTO_INCREMENT CREATE_TIME UPDATE_TIME CHECK_TIME TABLE_COLLATION CHECKSUM CREATE_OPTIONS TABLE_COMMENT MAX_INDEX_LENGTH TEMPORARY +SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=CONCAT('test',0x00,'1'); +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ENGINE VERSION ROW_FORMAT TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE AUTO_INCREMENT CREATE_TIME UPDATE_TIME CHECK_TIME TABLE_COLLATION CHECKSUM CREATE_OPTIONS TABLE_COMMENT MAX_INDEX_LENGTH TEMPORARY +DROP TABLE t; +CREATE TABLE `a/~.b` (a INT); +SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='a/~.b'; +TABLE_SCHEMA TABLE_NAME +test a/~.b +DROP TABLE `a/~.b`; +CREATE DATABASE `a/~.b`; +CREATE TABLE `a/~.b`.t1 (a INT); +SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='a/~.b'; +TABLE_SCHEMA TABLE_NAME +a/~.b t1 +DROP DATABASE `a/~.b`; +# # End of 10.2 Test # # diff --git a/mysql-test/main/information_schema.test b/mysql-test/main/information_schema.test index 71e700f3f18..0afb2daed34 100644 --- a/mysql-test/main/information_schema.test +++ b/mysql-test/main/information_schema.test @@ -1951,6 +1951,27 @@ SELECT * FROM v LIMIT ROWS EXAMINED 9; DROP VIEW v; --echo # +--echo # MDEV-23408 Wrong result upon query from I_S and further Assertion `!alias_arg || strlen(alias_arg->str) == alias_arg->length' failed with certain connection charset +--echo # + +# Expect empty sets if requested TABLE_NAME or TABLE_SCHEMA with zero bytes +CREATE TABLE t (a INT); +SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=CONCAT('t',0x00,'1'); +SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=CONCAT('test',0x00,'1'); +DROP TABLE t; + +# Make sure check_table_name() does not reject special characters +CREATE TABLE `a/~.b` (a INT); +SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='a/~.b'; +DROP TABLE `a/~.b`; + +# Make sure check_db_name() does not reject special characters +CREATE DATABASE `a/~.b`; +CREATE TABLE `a/~.b`.t1 (a INT); +SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='a/~.b'; +DROP DATABASE `a/~.b`; + +--echo # --echo # End of 10.2 Test --echo # diff --git a/mysql-test/main/sp-code.result b/mysql-test/main/sp-code.result index 46324c534e8..2b5f7374ce6 100644 --- a/mysql-test/main/sp-code.result +++ b/mysql-test/main/sp-code.result @@ -972,6 +972,30 @@ DROP PROCEDURE testp_bug11763507; DROP FUNCTION testf_bug11763507; #END OF BUG#11763507 test. # +# MDEV-23408 Wrong result upon query from I_S and further Assertion `!alias_arg || strlen(alias_arg->str) == alias_arg->length' failed with certain connection charset +# +SET NAMES utf8; +SET SESSION character_set_connection=latin1; +CREATE PROCEDURE p1() +BEGIN +DECLARE a VARCHAR(10) CHARACTER SET utf8; +SET a='ä'; +SELECT a, 'ä' AS b; +END; +$$ +SHOW PROCEDURE CODE p1; +Pos Instruction +0 set a@0 NULL +1 set a@0 'ä' +2 stmt 0 "SELECT a, 'ä' AS b" +CALL p1; +a b +ä ä +DROP PROCEDURE p1; +# +# End of 10.2 tests +# +# # MDEV-13581 ROW TYPE OF t1 and t1%ROWTYPE for routine parameters # CREATE TABLE t1 (a INT, b TEXT); @@ -1329,3 +1353,6 @@ Pos Instruction 4 jump 2 5 hpop 1 drop function f1; +# +# End of 10.3 tests +# diff --git a/mysql-test/main/sp-code.test b/mysql-test/main/sp-code.test index e03ce5048fb..35c9d4b9da1 100644 --- a/mysql-test/main/sp-code.test +++ b/mysql-test/main/sp-code.test @@ -738,6 +738,30 @@ DROP FUNCTION testf_bug11763507; --echo # +--echo # MDEV-23408 Wrong result upon query from I_S and further Assertion `!alias_arg || strlen(alias_arg->str) == alias_arg->length' failed with certain connection charset +--echo # + +SET NAMES utf8; +SET SESSION character_set_connection=latin1; +DELIMITER $$; +CREATE PROCEDURE p1() +BEGIN + DECLARE a VARCHAR(10) CHARACTER SET utf8; + SET a='ä'; + SELECT a, 'ä' AS b; +END; +$$ +DELIMITER ;$$ +SHOW PROCEDURE CODE p1; +CALL p1; +DROP PROCEDURE p1; + +--echo # +--echo # End of 10.2 tests +--echo # + + +--echo # --echo # MDEV-13581 ROW TYPE OF t1 and t1%ROWTYPE for routine parameters --echo # @@ -947,3 +971,7 @@ end| delimiter ;| show function code f1; drop function f1; + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/mysql-test/main/view.result b/mysql-test/main/view.result index def2f530978..34dd8f3c8dc 100644 --- a/mysql-test/main/view.result +++ b/mysql-test/main/view.result @@ -6820,6 +6820,17 @@ SELECT 1 FROM (SELECT count(((SELECT i1 FROM v1))) FROM v1) dt ; drop view v1; drop table t1; # +# MDEV-26299: Some views force server (and mysqldump) to generate +# invalid SQL for their definitions +# +create view v1 as +select * from +(select +"12345678901234567890123456789012345678901234567890123456789012345") as t1; +drop view v1; +CREATE VIEW v1 AS select `t1`.`12345678901234567890123456789012345678901234567890123456789012345` AS `Name_exp_1` from (select '12345678901234567890123456789012345678901234567890123456789012345') `t1`; +drop view v1; +# # End of 10.2 tests # # diff --git a/mysql-test/main/view.test b/mysql-test/main/view.test index 82dfb4c2ea6..7dd5f63396e 100644 --- a/mysql-test/main/view.test +++ b/mysql-test/main/view.test @@ -6548,6 +6548,25 @@ SELECT 1 FROM (SELECT count(((SELECT i1 FROM v1))) FROM v1) dt ; drop view v1; drop table t1; + +--echo # +--echo # MDEV-26299: Some views force server (and mysqldump) to generate +--echo # invalid SQL for their definitions +--echo # + +create view v1 as + select * from + (select + "12345678901234567890123456789012345678901234567890123456789012345") as t1; + +let $definition=`select VIEW_DEFINITION from information_schema.views where TABLE_NAME="v1"`; + +drop view v1; + +eval CREATE VIEW v1 AS $definition; + +drop view v1; + --echo # --echo # End of 10.2 tests --echo # diff --git a/mysql-test/main/xa.result b/mysql-test/main/xa.result index 4717d51b09c..725dc99bfce 100644 --- a/mysql-test/main/xa.result +++ b/mysql-test/main/xa.result @@ -395,6 +395,21 @@ Message XAER_RMFAIL: The command cannot be executed when global transaction is i xa commit 'foo'; drop table t1; # +# MDEV-22445 Crash on HANDLER READ NEXT after XA PREPARE +# +CREATE TABLE t (a INT KEY) ENGINE=InnoDB; +HANDLER t OPEN AS t; +XA START '0'; +SELECT * FROM t; +a +XA END '0'; +XA PREPARE '0'; +HANDLER t READ NEXT; +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state +# Cleanup +XA COMMIT '0'; +DROP TABLE t; +# # End of 10.2 tests # XA BEGIN 'xid'; diff --git a/mysql-test/main/xa.test b/mysql-test/main/xa.test index 33d4f69b7d2..5f122a215b5 100644 --- a/mysql-test/main/xa.test +++ b/mysql-test/main/xa.test @@ -532,6 +532,23 @@ xa commit 'foo'; drop table t1; --echo # +--echo # MDEV-22445 Crash on HANDLER READ NEXT after XA PREPARE +--echo # + +CREATE TABLE t (a INT KEY) ENGINE=InnoDB; +HANDLER t OPEN AS t; +XA START '0'; +SELECT * FROM t; +XA END '0'; +XA PREPARE '0'; +--error ER_XAER_RMFAIL +HANDLER t READ NEXT; + +--echo # Cleanup +XA COMMIT '0'; +DROP TABLE t; + +--echo # --echo # End of 10.2 tests --echo # diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 52e772991bd..d54c01e6db2 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -426,6 +426,7 @@ sub check_wsrep_support() { my $my_print_defaults_exe= mtr_exe_maybe_exists( "$bindir/extra/my_print_defaults", + "$bindir/extra/Debug/my_print_defaults", "$path_client_bindir/my_print_defaults"); my $epath= ""; if ($my_print_defaults_exe ne "") { @@ -1422,6 +1423,7 @@ sub command_line_setup { { $path_client_bindir= mtr_path_exists("$bindir/client_release", "$bindir/client_debug", + "$bindir/client/debug", "$bindir/client$opt_vs_config", "$bindir/client", "$bindir/bin"); diff --git a/mysql-test/suite/galera/r/galera_ftwrl_drain.result b/mysql-test/suite/galera/r/galera_ftwrl_drain.result index 751811b88fd..f90e6dfcdfd 100644 --- a/mysql-test/suite/galera/r/galera_ftwrl_drain.result +++ b/mysql-test/suite/galera/r/galera_ftwrl_drain.result @@ -8,9 +8,9 @@ connection node_2; SET SESSION wsrep_sync_wait = 0; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; -SELECT COUNT(*) = 0 FROM t1; -COUNT(*) = 0 -1 +SELECT COUNT(*) AS EXPECT_0 FROM t1; +EXPECT_0 +0 connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; connection node_2a; FLUSH TABLES WITH READ LOCK;; @@ -27,12 +27,12 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction connection node_2a; UNLOCK TABLES; connection node_2; -SELECT COUNT(*) = 1 FROM t1; -COUNT(*) = 1 +SELECT COUNT(*) AS EXPECT_1 FROM t1; +EXPECT_1 1 INSERT INTO t1 VALUES (3); connection node_1; -SELECT COUNT(*) = 2 FROM t1; -COUNT(*) = 2 -1 +SELECT COUNT(*) AS EXPECT_2 FROM t1; +EXPECT_2 +2 DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_ftwrl_drain.test b/mysql-test/suite/galera/t/galera_ftwrl_drain.test index 690e890cdea..9ed93643b3f 100644 --- a/mysql-test/suite/galera/t/galera_ftwrl_drain.test +++ b/mysql-test/suite/galera/t/galera_ftwrl_drain.test @@ -18,7 +18,8 @@ CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB; --connection node_2 - +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1' +--source include/wait_condition.inc --let $galera_sync_point = apply_monitor_slave_enter_sync --source include/galera_set_sync_point.inc @@ -31,7 +32,7 @@ SET SESSION wsrep_sync_wait = 0; # Wait until applier has blocked --source include/galera_wait_sync_point.inc -SELECT COUNT(*) = 0 FROM t1; +SELECT COUNT(*) AS EXPECT_0 FROM t1; --connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 --connection node_2a @@ -61,9 +62,11 @@ INSERT INTO t2 VALUES (2); UNLOCK TABLES; --connection node_2 -SELECT COUNT(*) = 1 FROM t1; +--let $wait_condition = SELECT COUNT(*) = 1 FROM t1 +--source include/wait_condition.inc +SELECT COUNT(*) AS EXPECT_1 FROM t1; INSERT INTO t1 VALUES (3); --connection node_1 -SELECT COUNT(*) = 2 FROM t1; +SELECT COUNT(*) AS EXPECT_2 FROM t1; DROP TABLE t1; diff --git a/mysql-test/suite/gcol/inc/gcol_column_def_options.inc b/mysql-test/suite/gcol/inc/gcol_column_def_options.inc index f4350d25ae9..17e926758ee 100644 --- a/mysql-test/suite/gcol/inc/gcol_column_def_options.inc +++ b/mysql-test/suite/gcol/inc/gcol_column_def_options.inc @@ -585,3 +585,14 @@ ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7, --disable_info DROP TABLE t1; --enable_warnings + +--echo # +--echo # MDEV-26262 frm is corrupted after ER_EXPRESSION_REFERS_TO_UNINIT_FIELD +--echo # + +--error ER_EXPRESSION_REFERS_TO_UNINIT_FIELD +CREATE TABLE MDEV_26262 (a INT,b INT AS (b) VIRTUAL); + +--let SEARCH_FILE=$MYSQLTEST_VARDIR/log/mysqld.1.err +--let SEARCH_PATTERN=Incorrect information in file: './test/MDEV_26262.frm' +--source include/search_pattern_in_file.inc diff --git a/mysql-test/suite/gcol/r/gcol_column_def_options_innodb.result b/mysql-test/suite/gcol/r/gcol_column_def_options_innodb.result index 6da3f3c14d3..8448a522602 100644 --- a/mysql-test/suite/gcol/r/gcol_column_def_options_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_column_def_options_innodb.result @@ -699,6 +699,12 @@ ADD COLUMN c INT AS (1 + DEFAULT(a)) VIRTUAL; affected rows: 1 info: Records: 1 Duplicates: 0 Warnings: 0 DROP TABLE t1; +# +# MDEV-26262 frm is corrupted after ER_EXPRESSION_REFERS_TO_UNINIT_FIELD +# +CREATE TABLE MDEV_26262 (a INT,b INT AS (b) VIRTUAL); +ERROR 01000: Expression for field `b` is referring to uninitialized field `b` +NOT FOUND /Incorrect information in file: './test/MDEV_26262.frm'/ in mysqld.1.err DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/mysql-test/suite/gcol/r/gcol_column_def_options_myisam.result b/mysql-test/suite/gcol/r/gcol_column_def_options_myisam.result index 0d7aaeab1fa..d1b4d490049 100644 --- a/mysql-test/suite/gcol/r/gcol_column_def_options_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_column_def_options_myisam.result @@ -699,6 +699,12 @@ ADD COLUMN c INT AS (1 + DEFAULT(a)) VIRTUAL; affected rows: 1 info: Records: 1 Duplicates: 0 Warnings: 0 DROP TABLE t1; +# +# MDEV-26262 frm is corrupted after ER_EXPRESSION_REFERS_TO_UNINIT_FIELD +# +CREATE TABLE MDEV_26262 (a INT,b INT AS (b) VIRTUAL); +ERROR 01000: Expression for field `b` is referring to uninitialized field `b` +NOT FOUND /Incorrect information in file: './test/MDEV_26262.frm'/ in mysqld.1.err DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/mysql-test/suite/innodb/r/default_row_format_create,redundant.rdiff b/mysql-test/suite/innodb/r/default_row_format_create,redundant.rdiff index fbf1d914f5b..2597d014636 100644 --- a/mysql-test/suite/innodb/r/default_row_format_create,redundant.rdiff +++ b/mysql-test/suite/innodb/r/default_row_format_create,redundant.rdiff @@ -20,3 +20,12 @@ SET @save_format = @@GLOBAL.innodb_default_row_format; SET GLOBAL innodb_default_row_format = redundant; CREATE TABLE t1 (c1 INT) ENGINE=InnoDB; +@@ -49,7 +49,7 @@ + ERROR HY000: Can't create table `test`.`t` (errno: 140 "Wrong create options") + SHOW WARNINGS; + Level Code Message +-Warning 1478 InnoDB: PAGE_COMPRESSED requires PAGE_COMPRESSION_LEVEL or innodb_compression_level > 0 ++Warning 140 InnoDB: PAGE_COMPRESSED table can't have ROW_TYPE=REDUNDANT + Error 1005 Can't create table `test`.`t` (errno: 140 "Wrong create options") + Warning 1030 Got error 140 "Wrong create options" from storage engine InnoDB + CREATE TABLE t(c INT) ENGINE=InnoDB page_compressed=1 page_compression_level=1; diff --git a/mysql-test/suite/innodb/r/default_row_format_create.result b/mysql-test/suite/innodb/r/default_row_format_create.result index 262e8bc7f19..50adc757b62 100644 --- a/mysql-test/suite/innodb/r/default_row_format_create.result +++ b/mysql-test/suite/innodb/r/default_row_format_create.result @@ -42,3 +42,26 @@ SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary t1 InnoDB # Redundant # # # # # # NULL # NULL NULL latin1_swedish_ci NULL 0 N DROP TABLE t1; +SET @save_level=@@GLOBAL.innodb_compression_level; +SET GLOBAL innodb_compression_level=0; +CREATE TABLE t(c INT) ENGINE=InnoDB page_compressed=1; +ERROR HY000: Can't create table `test`.`t` (errno: 140 "Wrong create options") +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: PAGE_COMPRESSED requires PAGE_COMPRESSION_LEVEL or innodb_compression_level > 0 +Error 1005 Can't create table `test`.`t` (errno: 140 "Wrong create options") +Warning 1030 Got error 140 "Wrong create options" from storage engine InnoDB +CREATE TABLE t(c INT) ENGINE=InnoDB page_compressed=1 page_compression_level=1; +DROP TABLE IF EXISTS t; +SET GLOBAL innodb_compression_level=1; +CREATE TABLE t(c INT) ENGINE=InnoDB page_compressed=1; +DROP TABLE IF EXISTS t; +SET GLOBAL innodb_compression_level=1; +CREATE TABLE t(a INT)ENGINE=InnoDB ROW_FORMAT=DYNAMIC page_compressed=1; +SET GLOBAL innodb_compression_level=0; +ALTER TABLE t FORCE, ROW_FORMAT=DEFAULT, ALGORITHM=INPLACE; +ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'PAGE_COMPRESSED' +ALTER TABLE t FORCE, ROW_FORMAT=DEFAULT, ALGORITHM=COPY; +ERROR HY000: Can't create table `test`.`t` (errno: 140 "Wrong create options") +DROP TABLE t; +SET GLOBAL innodb_compression_level=@save_level; diff --git a/mysql-test/suite/innodb/r/update_time.result b/mysql-test/suite/innodb/r/update_time.result index d8b9069b1ae..96d1af4c09c 100644 --- a/mysql-test/suite/innodb/r/update_time.result +++ b/mysql-test/suite/innodb/r/update_time.result @@ -24,8 +24,7 @@ SELECT COUNT(*) FROM information_schema.innodb_buffer_page WHERE table_name = '`test`.`t`'; COUNT(*) 1 -# INSERT lots of data in table 'big': begin -# INSERT lots of data in table 'big': end +INSERT INTO big SELECT REPEAT('a', 1024) FROM seq_1_to_10240; SELECT COUNT(*) FROM information_schema.innodb_buffer_page WHERE table_name = '`test`.`t`'; COUNT(*) diff --git a/mysql-test/suite/innodb/t/default_row_format_create.test b/mysql-test/suite/innodb/t/default_row_format_create.test index 03a7ebd3752..534a7312620 100644 --- a/mysql-test/suite/innodb/t/default_row_format_create.test +++ b/mysql-test/suite/innodb/t/default_row_format_create.test @@ -44,3 +44,28 @@ TRUNCATE TABLE t1; --replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # SHOW TABLE STATUS LIKE 't1'; DROP TABLE t1; + +SET @save_level=@@GLOBAL.innodb_compression_level; +SET GLOBAL innodb_compression_level=0; +--error ER_CANT_CREATE_TABLE +CREATE TABLE t(c INT) ENGINE=InnoDB page_compressed=1; +SHOW WARNINGS; +--disable_warnings +--error 0,ER_CANT_CREATE_TABLE +CREATE TABLE t(c INT) ENGINE=InnoDB page_compressed=1 page_compression_level=1; +DROP TABLE IF EXISTS t; +SET GLOBAL innodb_compression_level=1; +--error 0,ER_CANT_CREATE_TABLE +CREATE TABLE t(c INT) ENGINE=InnoDB page_compressed=1; +DROP TABLE IF EXISTS t; +--enable_warnings + +SET GLOBAL innodb_compression_level=1; +CREATE TABLE t(a INT)ENGINE=InnoDB ROW_FORMAT=DYNAMIC page_compressed=1; +SET GLOBAL innodb_compression_level=0; +--error ER_ILLEGAL_HA_CREATE_OPTION +ALTER TABLE t FORCE, ROW_FORMAT=DEFAULT, ALGORITHM=INPLACE; +--error ER_CANT_CREATE_TABLE +ALTER TABLE t FORCE, ROW_FORMAT=DEFAULT, ALGORITHM=COPY; +DROP TABLE t; +SET GLOBAL innodb_compression_level=@save_level; diff --git a/mysql-test/suite/innodb/t/update_time-master.opt b/mysql-test/suite/innodb/t/update_time-master.opt index 9f283a9503f..f0fd647546d 100644 --- a/mysql-test/suite/innodb/t/update_time-master.opt +++ b/mysql-test/suite/innodb/t/update_time-master.opt @@ -1 +1 @@ ---innodb-buffer-pool-size=10M +--innodb-buffer-pool-size=5M diff --git a/mysql-test/suite/innodb/t/update_time.test b/mysql-test/suite/innodb/t/update_time.test index a95c5171e9b..fd1e082f5f2 100644 --- a/mysql-test/suite/innodb/t/update_time.test +++ b/mysql-test/suite/innodb/t/update_time.test @@ -10,6 +10,7 @@ -- source include/not_embedded.inc # This test is slow on buildbot. --source include/big_test.inc +--source include/have_sequence.inc CREATE TABLE t (a INT) ENGINE=INNODB; @@ -33,18 +34,7 @@ SELECT COUNT(*) FROM information_schema.innodb_buffer_page WHERE table_name = '`test`.`t`'; # evict table 't' by inserting as much data as the BP size itself --- echo # INSERT lots of data in table 'big': begin --- disable_query_log -BEGIN; --- let $i = 10240 -while ($i) -{ - INSERT INTO big VALUES (REPEAT('a', 1024)); - dec $i; -} -COMMIT; --- enable_query_log --- echo # INSERT lots of data in table 'big': end +INSERT INTO big SELECT REPEAT('a', 1024) FROM seq_1_to_10240; # confirm that all pages for table 't' have been evicted SELECT COUNT(*) FROM information_schema.innodb_buffer_page diff --git a/mysql-test/suite/innodb_fts/r/basic.result b/mysql-test/suite/innodb_fts/r/basic.result index b3fd94509c3..a98de60674a 100644 --- a/mysql-test/suite/innodb_fts/r/basic.result +++ b/mysql-test/suite/innodb_fts/r/basic.result @@ -313,9 +313,7 @@ FTS_DOC_ID 65536 131071 drop table t1; -call mtr.add_suppression("\\[ERROR\\] InnoDB: Doc ID 20030101000000 is too big. Its difference with largest used Doc ID 0 cannot exceed or equal to 65535"); CREATE TABLE t1 (FTS_DOC_ID BIGINT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), FULLTEXT(title)) ENGINE=InnoDB; INSERT INTO t1 VALUES (NULL, NULL), (20030101000000, 20030102000000); -ERROR HY000: Invalid InnoDB FTS Doc ID DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/r/bug_32831765.result b/mysql-test/suite/innodb_fts/r/bug_32831765.result new file mode 100644 index 00000000000..1b828f4266b --- /dev/null +++ b/mysql-test/suite/innodb_fts/r/bug_32831765.result @@ -0,0 +1,131 @@ +# +# Bug#32831765 SERVER HITS OOM CONDITION WHEN LOADING TWO +# INNODB TABLES WITH FTS INDEXES +# +create table t1 ( `id` int unsigned NOT NULL AUTO_INCREMENT, `col01` text, +`col02` text, `col03` text, `col04` text, `col05` text, `col06` text, `col07` +text, `col08` text, `col09` text, `col10` text, `col11` text, `col12` text, +`col13` text, `col14` text, `col15` text, `col16` text, `col17` text, `col18` +text, `col19` text, `col20` text, `col21` text, `col22` text, `col23` text, +`col24` text, `col25` text, `col26` text, `col27` text, `col28` text, `col29` +text, `col30` text, PRIMARY KEY (`id`), FULLTEXT KEY (`col01`), FULLTEXT KEY +(`col02`), FULLTEXT KEY (`col03`), FULLTEXT KEY (`col04`), FULLTEXT KEY +(`col05`), FULLTEXT KEY (`col06`), FULLTEXT KEY (`col07`), FULLTEXT KEY +(`col08`), FULLTEXT KEY (`col09`), FULLTEXT KEY (`col10`), FULLTEXT KEY +(`col11`), FULLTEXT KEY (`col12`), FULLTEXT KEY (`col13`), FULLTEXT KEY +(`col14`), FULLTEXT KEY (`col15`), FULLTEXT KEY (`col16`), FULLTEXT KEY +(`col17`), FULLTEXT KEY (`col18`), FULLTEXT KEY (`col19`), FULLTEXT KEY +(`col20`), FULLTEXT KEY (`col21`), FULLTEXT KEY (`col22`), FULLTEXT KEY +(`col23`), FULLTEXT KEY (`col24`), FULLTEXT KEY (`col25`), FULLTEXT KEY +(`col26`), FULLTEXT KEY (`col27`), FULLTEXT KEY (`col28`), FULLTEXT KEY +(`col29`), FULLTEXT KEY (`col30`)) engine=innodb; +create table t2 ( `id` int unsigned NOT NULL AUTO_INCREMENT, `col01` text, +`col02` text, `col03` text, `col04` text, `col05` text, `col06` text, `col07` +text, `col08` text, `col09` text, `col10` text, `col11` text, `col12` text, +`col13` text, `col14` text, `col15` text, `col16` text, `col17` text, `col18` +text, `col19` text, `col20` text, `col21` text, `col22` text, `col23` text, +`col24` text, `col25` text, `col26` text, `col27` text, `col28` text, `col29` +text, `col30` text, PRIMARY KEY (`id`), FULLTEXT KEY (`col01`), FULLTEXT KEY +(`col02`), FULLTEXT KEY (`col03`), FULLTEXT KEY (`col04`), FULLTEXT KEY +(`col05`), FULLTEXT KEY (`col06`), FULLTEXT KEY (`col07`), FULLTEXT KEY +(`col08`), FULLTEXT KEY (`col09`), FULLTEXT KEY (`col10`), FULLTEXT KEY +(`col11`), FULLTEXT KEY (`col12`), FULLTEXT KEY (`col13`), FULLTEXT KEY +(`col14`), FULLTEXT KEY (`col15`), FULLTEXT KEY (`col16`), FULLTEXT KEY +(`col17`), FULLTEXT KEY (`col18`), FULLTEXT KEY (`col19`), FULLTEXT KEY +(`col20`), FULLTEXT KEY (`col21`), FULLTEXT KEY (`col22`), FULLTEXT KEY +(`col23`), FULLTEXT KEY (`col24`), FULLTEXT KEY (`col25`), FULLTEXT KEY +(`col26`), FULLTEXT KEY (`col27`), FULLTEXT KEY (`col28`), FULLTEXT KEY +(`col29`), FULLTEXT KEY (`col30`)) engine=innodb; +create table t3 ( `id` int unsigned NOT NULL AUTO_INCREMENT, `col01` text, +`col02` text, `col03` text, `col04` text, `col05` text, `col06` text, `col07` +text, `col08` text, `col09` text, `col10` text, `col11` text, `col12` text, +`col13` text, `col14` text, `col15` text, `col16` text, `col17` text, `col18` +text, `col19` text, `col20` text, `col21` text, `col22` text, `col23` text, +`col24` text, `col25` text, `col26` text, `col27` text, `col28` text, `col29` +text, `col30` text, PRIMARY KEY (`id`), FULLTEXT KEY (`col01`), FULLTEXT KEY +(`col02`), FULLTEXT KEY (`col03`), FULLTEXT KEY (`col04`), FULLTEXT KEY +(`col05`), FULLTEXT KEY (`col06`), FULLTEXT KEY (`col07`), FULLTEXT KEY +(`col08`), FULLTEXT KEY (`col09`), FULLTEXT KEY (`col10`), FULLTEXT KEY +(`col11`), FULLTEXT KEY (`col12`), FULLTEXT KEY (`col13`), FULLTEXT KEY +(`col14`), FULLTEXT KEY (`col15`), FULLTEXT KEY (`col16`), FULLTEXT KEY +(`col17`), FULLTEXT KEY (`col18`), FULLTEXT KEY (`col19`), FULLTEXT KEY +(`col20`), FULLTEXT KEY (`col21`), FULLTEXT KEY (`col22`), FULLTEXT KEY +(`col23`), FULLTEXT KEY (`col24`), FULLTEXT KEY (`col25`), FULLTEXT KEY +(`col26`), FULLTEXT KEY (`col27`), FULLTEXT KEY (`col28`), FULLTEXT KEY +(`col29`), FULLTEXT KEY (`col30`)) engine=innodb; +create table t4 ( `id` int unsigned NOT NULL AUTO_INCREMENT, `col01` text, +`col02` text, `col03` text, `col04` text, `col05` text, `col06` text, `col07` +text, `col08` text, `col09` text, `col10` text, `col11` text, `col12` text, +`col13` text, `col14` text, `col15` text, `col16` text, `col17` text, `col18` +text, `col19` text, `col20` text, `col21` text, `col22` text, `col23` text, +`col24` text, `col25` text, `col26` text, `col27` text, `col28` text, `col29` +text, `col30` text, PRIMARY KEY (`id`), FULLTEXT KEY (`col01`), FULLTEXT KEY +(`col02`), FULLTEXT KEY (`col03`), FULLTEXT KEY (`col04`), FULLTEXT KEY +(`col05`), FULLTEXT KEY (`col06`), FULLTEXT KEY (`col07`), FULLTEXT KEY +(`col08`), FULLTEXT KEY (`col09`), FULLTEXT KEY (`col10`), FULLTEXT KEY +(`col11`), FULLTEXT KEY (`col12`), FULLTEXT KEY (`col13`), FULLTEXT KEY +(`col14`), FULLTEXT KEY (`col15`), FULLTEXT KEY (`col16`), FULLTEXT KEY +(`col17`), FULLTEXT KEY (`col18`), FULLTEXT KEY (`col19`), FULLTEXT KEY +(`col20`), FULLTEXT KEY (`col21`), FULLTEXT KEY (`col22`), FULLTEXT KEY +(`col23`), FULLTEXT KEY (`col24`), FULLTEXT KEY (`col25`), FULLTEXT KEY +(`col26`), FULLTEXT KEY (`col27`), FULLTEXT KEY (`col28`), FULLTEXT KEY +(`col29`), FULLTEXT KEY (`col30`)) engine=innodb; +#create procedure to inset into the table. +CREATE PROCEDURE `proc_insert`(IN tab_name VARCHAR(40)) +BEGIN +DECLARE i INT DEFAULT 1; +SET @insert_tbl =CONCAT('INSERT INTO ', tab_name, '( `col01`, `col02`, + `col03`, `col04`, `col05`, `col06`, `col07`, `col08`, `col09`, `col10`, + `col11`, `col12`, `col13`, `col14`, `col15`, `col16`, `col17`, `col18`, + `col19`, `col20`, `col21`, `col22`, `col23`, `col24`, `col25`, `col26`, + `col27`, `col28`, `col29`, `col30`) + VALUES ( MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), + MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), + MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), + MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), + MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), + MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), + MD5(RAND()))'); +PREPARE ins_stmt FROM @insert_tbl; +while (i <= 2000) DO +EXECUTE ins_stmt; +SET i = i + 1; +END WHILE; +DEALLOCATE PREPARE ins_stmt; +END | +SET @save_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,fts_optimize_wq_count_check"; +connect con1,localhost,root,,; +call proc_insert('t1'); +connect con2,localhost,root,,; +call proc_insert('t1'); +connect con3,localhost,root,,; +call proc_insert('t2'); +connect con4,localhost,root,,; +call proc_insert('t2'); +connect con5,localhost,root,,; +call proc_insert('t3'); +connect con6,localhost,root,,; +call proc_insert('t3'); +connect con7,localhost,root,,; +call proc_insert('t4'); +connection default; +call proc_insert('t4'); +SET GLOBAL debug_dbug= @save_dbug; +connection con1; +disconnect con1; +connection con2; +disconnect con2; +connection con3; +disconnect con3; +connection con4; +disconnect con4; +connection con5; +disconnect con5; +connection con6; +disconnect con6; +connection con7; +disconnect con7; +connection default; +DROP TABLE t1,t2,t3,t4; +DROP PROCEDURE proc_insert; diff --git a/mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result b/mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result index 9995a09faf7..afe452a137e 100644 --- a/mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result +++ b/mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result @@ -968,3 +968,24 @@ SELECT * FROM information_schema.innodb_ft_deleted; DOC_ID DROP TABLE t1; SET GLOBAL innodb_ft_aux_table=DEFAULT; +# +# MDEV-19522 InnoDB commit fails when FTS_DOC_ID value +# is greater than 4294967295 +# +CREATE TABLE t1( +FTS_DOC_ID BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, +f1 TEXT, f2 TEXT, PRIMARY KEY (FTS_DOC_ID), +FULLTEXT KEY (f1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,'txt','bbb'); +UPDATE t1 SET FTS_DOC_ID = 4294967298; +SELECT * FROM t1 WHERE match(f1) against("txt"); +FTS_DOC_ID f1 f2 +4294967298 txt bbb +SET @@session.insert_id = 100000000000; +INSERT INTO t1(f1, f2) VALUES ('aaa', 'bbb'); +CREATE FULLTEXT INDEX i ON t1 (f2); +SELECT * FROM t1 WHERE match(f2) against("bbb"); +FTS_DOC_ID f1 f2 +4294967298 txt bbb +100000000000 aaa bbb +DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/t/basic.test b/mysql-test/suite/innodb_fts/t/basic.test index 7a5c83ffb06..53ad978a5b1 100644 --- a/mysql-test/suite/innodb_fts/t/basic.test +++ b/mysql-test/suite/innodb_fts/t/basic.test @@ -277,9 +277,7 @@ insert into t1(f1, f2) values(3, "This is the third record"); select FTS_DOC_ID from t1; drop table t1; -call mtr.add_suppression("\\[ERROR\\] InnoDB: Doc ID 20030101000000 is too big. Its difference with largest used Doc ID 0 cannot exceed or equal to 65535"); CREATE TABLE t1 (FTS_DOC_ID BIGINT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), FULLTEXT(title)) ENGINE=InnoDB; ---error 182 INSERT INTO t1 VALUES (NULL, NULL), (20030101000000, 20030102000000); DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/t/bug_32831765.test b/mysql-test/suite/innodb_fts/t/bug_32831765.test new file mode 100644 index 00000000000..a4551cf91ef --- /dev/null +++ b/mysql-test/suite/innodb_fts/t/bug_32831765.test @@ -0,0 +1,164 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/big_test.inc + +--echo # +--echo # Bug#32831765 SERVER HITS OOM CONDITION WHEN LOADING TWO +--echo # INNODB TABLES WITH FTS INDEXES +--echo # + +create table t1 ( `id` int unsigned NOT NULL AUTO_INCREMENT, `col01` text, +`col02` text, `col03` text, `col04` text, `col05` text, `col06` text, `col07` +text, `col08` text, `col09` text, `col10` text, `col11` text, `col12` text, +`col13` text, `col14` text, `col15` text, `col16` text, `col17` text, `col18` +text, `col19` text, `col20` text, `col21` text, `col22` text, `col23` text, +`col24` text, `col25` text, `col26` text, `col27` text, `col28` text, `col29` +text, `col30` text, PRIMARY KEY (`id`), FULLTEXT KEY (`col01`), FULLTEXT KEY +(`col02`), FULLTEXT KEY (`col03`), FULLTEXT KEY (`col04`), FULLTEXT KEY +(`col05`), FULLTEXT KEY (`col06`), FULLTEXT KEY (`col07`), FULLTEXT KEY +(`col08`), FULLTEXT KEY (`col09`), FULLTEXT KEY (`col10`), FULLTEXT KEY +(`col11`), FULLTEXT KEY (`col12`), FULLTEXT KEY (`col13`), FULLTEXT KEY +(`col14`), FULLTEXT KEY (`col15`), FULLTEXT KEY (`col16`), FULLTEXT KEY +(`col17`), FULLTEXT KEY (`col18`), FULLTEXT KEY (`col19`), FULLTEXT KEY +(`col20`), FULLTEXT KEY (`col21`), FULLTEXT KEY (`col22`), FULLTEXT KEY +(`col23`), FULLTEXT KEY (`col24`), FULLTEXT KEY (`col25`), FULLTEXT KEY +(`col26`), FULLTEXT KEY (`col27`), FULLTEXT KEY (`col28`), FULLTEXT KEY +(`col29`), FULLTEXT KEY (`col30`)) engine=innodb; + +create table t2 ( `id` int unsigned NOT NULL AUTO_INCREMENT, `col01` text, +`col02` text, `col03` text, `col04` text, `col05` text, `col06` text, `col07` +text, `col08` text, `col09` text, `col10` text, `col11` text, `col12` text, +`col13` text, `col14` text, `col15` text, `col16` text, `col17` text, `col18` +text, `col19` text, `col20` text, `col21` text, `col22` text, `col23` text, +`col24` text, `col25` text, `col26` text, `col27` text, `col28` text, `col29` +text, `col30` text, PRIMARY KEY (`id`), FULLTEXT KEY (`col01`), FULLTEXT KEY +(`col02`), FULLTEXT KEY (`col03`), FULLTEXT KEY (`col04`), FULLTEXT KEY +(`col05`), FULLTEXT KEY (`col06`), FULLTEXT KEY (`col07`), FULLTEXT KEY +(`col08`), FULLTEXT KEY (`col09`), FULLTEXT KEY (`col10`), FULLTEXT KEY +(`col11`), FULLTEXT KEY (`col12`), FULLTEXT KEY (`col13`), FULLTEXT KEY +(`col14`), FULLTEXT KEY (`col15`), FULLTEXT KEY (`col16`), FULLTEXT KEY +(`col17`), FULLTEXT KEY (`col18`), FULLTEXT KEY (`col19`), FULLTEXT KEY +(`col20`), FULLTEXT KEY (`col21`), FULLTEXT KEY (`col22`), FULLTEXT KEY +(`col23`), FULLTEXT KEY (`col24`), FULLTEXT KEY (`col25`), FULLTEXT KEY +(`col26`), FULLTEXT KEY (`col27`), FULLTEXT KEY (`col28`), FULLTEXT KEY +(`col29`), FULLTEXT KEY (`col30`)) engine=innodb; + + +create table t3 ( `id` int unsigned NOT NULL AUTO_INCREMENT, `col01` text, +`col02` text, `col03` text, `col04` text, `col05` text, `col06` text, `col07` +text, `col08` text, `col09` text, `col10` text, `col11` text, `col12` text, +`col13` text, `col14` text, `col15` text, `col16` text, `col17` text, `col18` +text, `col19` text, `col20` text, `col21` text, `col22` text, `col23` text, +`col24` text, `col25` text, `col26` text, `col27` text, `col28` text, `col29` +text, `col30` text, PRIMARY KEY (`id`), FULLTEXT KEY (`col01`), FULLTEXT KEY +(`col02`), FULLTEXT KEY (`col03`), FULLTEXT KEY (`col04`), FULLTEXT KEY +(`col05`), FULLTEXT KEY (`col06`), FULLTEXT KEY (`col07`), FULLTEXT KEY +(`col08`), FULLTEXT KEY (`col09`), FULLTEXT KEY (`col10`), FULLTEXT KEY +(`col11`), FULLTEXT KEY (`col12`), FULLTEXT KEY (`col13`), FULLTEXT KEY +(`col14`), FULLTEXT KEY (`col15`), FULLTEXT KEY (`col16`), FULLTEXT KEY +(`col17`), FULLTEXT KEY (`col18`), FULLTEXT KEY (`col19`), FULLTEXT KEY +(`col20`), FULLTEXT KEY (`col21`), FULLTEXT KEY (`col22`), FULLTEXT KEY +(`col23`), FULLTEXT KEY (`col24`), FULLTEXT KEY (`col25`), FULLTEXT KEY +(`col26`), FULLTEXT KEY (`col27`), FULLTEXT KEY (`col28`), FULLTEXT KEY +(`col29`), FULLTEXT KEY (`col30`)) engine=innodb; + +create table t4 ( `id` int unsigned NOT NULL AUTO_INCREMENT, `col01` text, +`col02` text, `col03` text, `col04` text, `col05` text, `col06` text, `col07` +text, `col08` text, `col09` text, `col10` text, `col11` text, `col12` text, +`col13` text, `col14` text, `col15` text, `col16` text, `col17` text, `col18` +text, `col19` text, `col20` text, `col21` text, `col22` text, `col23` text, +`col24` text, `col25` text, `col26` text, `col27` text, `col28` text, `col29` +text, `col30` text, PRIMARY KEY (`id`), FULLTEXT KEY (`col01`), FULLTEXT KEY +(`col02`), FULLTEXT KEY (`col03`), FULLTEXT KEY (`col04`), FULLTEXT KEY +(`col05`), FULLTEXT KEY (`col06`), FULLTEXT KEY (`col07`), FULLTEXT KEY +(`col08`), FULLTEXT KEY (`col09`), FULLTEXT KEY (`col10`), FULLTEXT KEY +(`col11`), FULLTEXT KEY (`col12`), FULLTEXT KEY (`col13`), FULLTEXT KEY +(`col14`), FULLTEXT KEY (`col15`), FULLTEXT KEY (`col16`), FULLTEXT KEY +(`col17`), FULLTEXT KEY (`col18`), FULLTEXT KEY (`col19`), FULLTEXT KEY +(`col20`), FULLTEXT KEY (`col21`), FULLTEXT KEY (`col22`), FULLTEXT KEY +(`col23`), FULLTEXT KEY (`col24`), FULLTEXT KEY (`col25`), FULLTEXT KEY +(`col26`), FULLTEXT KEY (`col27`), FULLTEXT KEY (`col28`), FULLTEXT KEY +(`col29`), FULLTEXT KEY (`col30`)) engine=innodb; + +delimiter |; + +--echo #create procedure to inset into the table. +CREATE PROCEDURE `proc_insert`(IN tab_name VARCHAR(40)) +BEGIN + DECLARE i INT DEFAULT 1; + SET @insert_tbl =CONCAT('INSERT INTO ', tab_name, '( `col01`, `col02`, + `col03`, `col04`, `col05`, `col06`, `col07`, `col08`, `col09`, `col10`, + `col11`, `col12`, `col13`, `col14`, `col15`, `col16`, `col17`, `col18`, + `col19`, `col20`, `col21`, `col22`, `col23`, `col24`, `col25`, `col26`, + `col27`, `col28`, `col29`, `col30`) + VALUES ( MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), + MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), + MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), + MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), + MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), + MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), MD5(RAND()), + MD5(RAND()))'); + PREPARE ins_stmt FROM @insert_tbl; + while (i <= 2000) DO + EXECUTE ins_stmt; + SET i = i + 1; + END WHILE; + DEALLOCATE PREPARE ins_stmt; +END | + +delimiter ;| + +# Ensure that the number of SYNC requests will not exceed 1000. +SET @save_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,fts_optimize_wq_count_check"; + +connect (con1,localhost,root,,); +send call proc_insert('t1'); +connect (con2,localhost,root,,); +send call proc_insert('t1'); +connect (con3,localhost,root,,); +send call proc_insert('t2'); +connect (con4,localhost,root,,); +send call proc_insert('t2'); +connect (con5,localhost,root,,); +send call proc_insert('t3'); +connect (con6,localhost,root,,); +send call proc_insert('t3'); +connect (con7,localhost,root,,); +send call proc_insert('t4'); + +connection default; +call proc_insert('t4'); +SET GLOBAL debug_dbug= @save_dbug; + +connection con1; +reap; +disconnect con1; + +connection con2; +reap; +disconnect con2; + +connection con3; +reap; +disconnect con3; + +connection con4; +reap; +disconnect con4; + +connection con5; +reap; +disconnect con5; + +connection con6; +reap; +disconnect con6; + +connection con7; +reap; +disconnect con7; + +connection default; +DROP TABLE t1,t2,t3,t4; +DROP PROCEDURE proc_insert; diff --git a/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test b/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test index adc10886d66..b0bf2c669ad 100644 --- a/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test +++ b/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test @@ -942,3 +942,21 @@ SET GLOBAL innodb_ft_aux_table='test/t1'; SELECT * FROM information_schema.innodb_ft_deleted; DROP TABLE t1; SET GLOBAL innodb_ft_aux_table=DEFAULT; + +--echo # +--echo # MDEV-19522 InnoDB commit fails when FTS_DOC_ID value +--echo # is greater than 4294967295 +--echo # +CREATE TABLE t1( + FTS_DOC_ID BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + f1 TEXT, f2 TEXT, PRIMARY KEY (FTS_DOC_ID), + FULLTEXT KEY (f1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,'txt','bbb'); +UPDATE t1 SET FTS_DOC_ID = 4294967298; +SELECT * FROM t1 WHERE match(f1) against("txt"); +SET @@session.insert_id = 100000000000; +INSERT INTO t1(f1, f2) VALUES ('aaa', 'bbb'); +CREATE FULLTEXT INDEX i ON t1 (f2); +SELECT * FROM t1 WHERE match(f2) against("bbb"); +# Cleanup +DROP TABLE t1; diff --git a/mysql-test/suite/roles/rebuild_role_grants.result b/mysql-test/suite/roles/rebuild_role_grants.result index f8297d91024..b8d747537aa 100644 --- a/mysql-test/suite/roles/rebuild_role_grants.result +++ b/mysql-test/suite/roles/rebuild_role_grants.result @@ -65,3 +65,269 @@ drop role look, isp, xxx, ppp; connection default; disconnect con1; drop user nnnn@'%'; +CREATE USER u@localhost; +CREATE ROLE r1; +CREATE ROLE r2; +CREATE ROLE r3; +CREATE ROLE r4; +CREATE ROLE r5; +CREATE ROLE r6; +CREATE ROLE r7; +CREATE ROLE r8; +CREATE ROLE r9; +CREATE ROLE r10; +CREATE ROLE r11; +CREATE ROLE r12; +CREATE ROLE r13; +CREATE ROLE r14; +CREATE ROLE r15; +CREATE ROLE r16; +CREATE ROLE r17; +CREATE ROLE r18; +CREATE ROLE r19; +CREATE ROLE r20; +CREATE ROLE r21; +CREATE ROLE r22; +CREATE ROLE r23; +CREATE ROLE r24; +CREATE ROLE r25; +CREATE ROLE r26; +CREATE ROLE r27; +CREATE ROLE r28; +CREATE ROLE r29; +CREATE ROLE r30; +CREATE ROLE r31; +CREATE ROLE r32; +CREATE ROLE r33; +CREATE ROLE r34; +CREATE ROLE r35; +CREATE ROLE r36; +CREATE ROLE r37; +CREATE ROLE r38; +CREATE ROLE r39; +CREATE ROLE r40; +CREATE ROLE r41; +CREATE ROLE r42; +CREATE ROLE r43; +CREATE ROLE r44; +CREATE ROLE r45; +CREATE ROLE r46; +CREATE ROLE r47; +CREATE ROLE r48; +CREATE ROLE r49; +CREATE ROLE r50; +CREATE ROLE r51; +CREATE ROLE r52; +CREATE ROLE r53; +CREATE ROLE r54; +CREATE ROLE r55; +CREATE ROLE r56; +CREATE ROLE r57; +CREATE ROLE r58; +CREATE ROLE r59; +CREATE ROLE r60; +CREATE ROLE r61; +CREATE ROLE r62; +CREATE ROLE r63; +CREATE ROLE r64; +CREATE ROLE r65; +CREATE ROLE r66; +CREATE ROLE r67; +CREATE ROLE r68; +CREATE ROLE r69; +CREATE ROLE r70; +CREATE ROLE r71; +CREATE ROLE r72; +CREATE ROLE r73; +CREATE ROLE r74; +CREATE ROLE r75; +CREATE ROLE r76; +CREATE ROLE r77; +CREATE ROLE r78; +CREATE ROLE r79; +CREATE ROLE r80; +CREATE ROLE r81; +CREATE ROLE r82; +CREATE ROLE r83; +CREATE ROLE r84; +CREATE ROLE r85; +CREATE ROLE r86; +CREATE ROLE r87; +CREATE ROLE r88; +CREATE ROLE r89; +CREATE ROLE r90; +CREATE ROLE r91; +CREATE ROLE r92; +CREATE ROLE r93; +CREATE ROLE r94; +CREATE ROLE r95; +CREATE ROLE r96; +CREATE ROLE r97; +CREATE ROLE r98; +CREATE ROLE r99; +CREATE ROLE r100; +CREATE ROLE r101; +CREATE ROLE r102; +CREATE ROLE r103; +CREATE ROLE r104; +CREATE ROLE r105; +CREATE ROLE r106; +CREATE ROLE r107; +CREATE ROLE r108; +CREATE ROLE r109; +CREATE ROLE r110; +CREATE ROLE r111; +CREATE ROLE r112; +CREATE ROLE r113; +CREATE ROLE r114; +CREATE ROLE r115; +CREATE ROLE r116; +CREATE ROLE r117; +CREATE ROLE r118; +CREATE ROLE r119; +CREATE ROLE r120; +CREATE ROLE r121; +CREATE ROLE r122; +CREATE ROLE r123; +CREATE ROLE r124; +CREATE ROLE r125; +CREATE ROLE r126; +CREATE ROLE r127; +CREATE ROLE r128; +CREATE ROLE n; +CREATE ROLE d WITH ADMIN n; +CREATE ROLE '%' WITH ADMIN u@localhost; +DROP ROLE n; +CREATE USER 't'; +DROP ROLE r1; +DROP ROLE r2; +DROP ROLE r3; +DROP ROLE r4; +DROP ROLE r5; +DROP ROLE r6; +DROP ROLE r7; +DROP ROLE r8; +DROP ROLE r9; +DROP ROLE r10; +DROP ROLE r11; +DROP ROLE r12; +DROP ROLE r13; +DROP ROLE r14; +DROP ROLE r15; +DROP ROLE r16; +DROP ROLE r17; +DROP ROLE r18; +DROP ROLE r19; +DROP ROLE r20; +DROP ROLE r21; +DROP ROLE r22; +DROP ROLE r23; +DROP ROLE r24; +DROP ROLE r25; +DROP ROLE r26; +DROP ROLE r27; +DROP ROLE r28; +DROP ROLE r29; +DROP ROLE r30; +DROP ROLE r31; +DROP ROLE r32; +DROP ROLE r33; +DROP ROLE r34; +DROP ROLE r35; +DROP ROLE r36; +DROP ROLE r37; +DROP ROLE r38; +DROP ROLE r39; +DROP ROLE r40; +DROP ROLE r41; +DROP ROLE r42; +DROP ROLE r43; +DROP ROLE r44; +DROP ROLE r45; +DROP ROLE r46; +DROP ROLE r47; +DROP ROLE r48; +DROP ROLE r49; +DROP ROLE r50; +DROP ROLE r51; +DROP ROLE r52; +DROP ROLE r53; +DROP ROLE r54; +DROP ROLE r55; +DROP ROLE r56; +DROP ROLE r57; +DROP ROLE r58; +DROP ROLE r59; +DROP ROLE r60; +DROP ROLE r61; +DROP ROLE r62; +DROP ROLE r63; +DROP ROLE r64; +DROP ROLE r65; +DROP ROLE r66; +DROP ROLE r67; +DROP ROLE r68; +DROP ROLE r69; +DROP ROLE r70; +DROP ROLE r71; +DROP ROLE r72; +DROP ROLE r73; +DROP ROLE r74; +DROP ROLE r75; +DROP ROLE r76; +DROP ROLE r77; +DROP ROLE r78; +DROP ROLE r79; +DROP ROLE r80; +DROP ROLE r81; +DROP ROLE r82; +DROP ROLE r83; +DROP ROLE r84; +DROP ROLE r85; +DROP ROLE r86; +DROP ROLE r87; +DROP ROLE r88; +DROP ROLE r89; +DROP ROLE r90; +DROP ROLE r91; +DROP ROLE r92; +DROP ROLE r93; +DROP ROLE r94; +DROP ROLE r95; +DROP ROLE r96; +DROP ROLE r97; +DROP ROLE r98; +DROP ROLE r99; +DROP ROLE r100; +DROP ROLE r101; +DROP ROLE r102; +DROP ROLE r103; +DROP ROLE r104; +DROP ROLE r105; +DROP ROLE r106; +DROP ROLE r107; +DROP ROLE r108; +DROP ROLE r109; +DROP ROLE r110; +DROP ROLE r111; +DROP ROLE r112; +DROP ROLE r113; +DROP ROLE r114; +DROP ROLE r115; +DROP ROLE r116; +DROP ROLE r117; +DROP ROLE r118; +DROP ROLE r119; +DROP ROLE r120; +DROP ROLE r121; +DROP ROLE r122; +DROP ROLE r123; +DROP ROLE r124; +DROP ROLE r125; +DROP ROLE r126; +DROP ROLE r127; +DROP ROLE r128; +DROP ROLE d; +DROP ROLE '%'; +DROP USER 't'; +DROP USER u@localhost; diff --git a/mysql-test/suite/roles/rebuild_role_grants.test b/mysql-test/suite/roles/rebuild_role_grants.test index 84dbdf78fb8..7007df0ecdd 100644 --- a/mysql-test/suite/roles/rebuild_role_grants.test +++ b/mysql-test/suite/roles/rebuild_role_grants.test @@ -67,3 +67,34 @@ drop role look, isp, xxx, ppp; connection default; disconnect con1; drop user nnnn@'%'; + +# +# MDEV-17964 Assertion `status == 0' failed in add_role_user_mapping_action +# upon CREATE USER and DROP ROLE +# +CREATE USER u@localhost; + +--let $n= 1 +while ($n < 129) +{ + eval CREATE ROLE r$n; + inc $n; +} + +CREATE ROLE n; +CREATE ROLE d WITH ADMIN n; +CREATE ROLE '%' WITH ADMIN u@localhost; +DROP ROLE n; +CREATE USER 't'; + +--let $n= 1 +while ($n < 129) +{ + eval DROP ROLE r$n; + inc $n; +} + +DROP ROLE d; +DROP ROLE '%'; +DROP USER 't'; +DROP USER u@localhost; diff --git a/mysql-test/suite/rpl/include/rpl_reset_slave_all_check.inc b/mysql-test/suite/rpl/include/rpl_reset_slave_all_check.inc new file mode 100644 index 00000000000..adbaf32ebd7 --- /dev/null +++ b/mysql-test/suite/rpl/include/rpl_reset_slave_all_check.inc @@ -0,0 +1,48 @@ +# This file ensures that a slave's id filtering variables (i.e. DO_DOMAIN_IDS, +# IGNORE_DOMAIN_IDS, and IGNORE_SERVER_IDS) are cleared after issuing +# `RESET SLAVE ALL`. +# +# param $_do_domain_ids Integer list of values to use for DO_DOMAIN_IDS +# param $_ignore_domain_ids Integer list of values to use for IGNORE_DOMAIN_IDS +# param $_ignore_server_ids Integer list of values to use for IGNORE_SERVER_IDS +# + +--echo # Id filtering variable values should be empty initially +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +let $ignore_server_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); + +if (`SELECT "$do_domain_ids_before" != "" OR + "$ignore_domain_ids_before" != "" OR + "$ignore_server_ids_before" != ""`) +{ + die("CHANGE MASTER TO id filter variables are not empty initially"); +} + + +--echo # Set id filtering variables +eval CHANGE MASTER TO DO_DOMAIN_IDS=$_do_domain_ids, IGNORE_DOMAIN_IDS=$_ignore_domain_ids, IGNORE_SERVER_IDS=$_ignore_server_ids, MASTER_USE_GTID=SLAVE_POS; +let $do_domain_ids_set= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_set= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +let $ignore_server_ids_set= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); +--echo # do domain id list: $do_domain_ids_set +--echo # ignore domain id list: $ignore_domain_ids_set +--echo # ignore server id list: $ignore_server_ids_set + + +--echo # RESET SLAVE ALL should clear values for all id filtering variables +RESET SLAVE ALL; +--replace_result $MASTER_MYPORT MASTER_MYPORT +eval change master to master_port=$MASTER_MYPORT, master_host='127.0.0.1', master_user='root'; +--source include/start_slave.inc +--source include/stop_slave.inc + +let $do_domain_ids_cleared= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_cleared= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +let $ignore_server_ids_cleared= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); +if (`SELECT "$do_domain_ids_cleared" != "" OR + "$ignore_domain_ids_cleared" != "" OR + "$ignore_server_ids_cleared" != ""`) +{ + die("RESET SLAVE ALL did not clear id filtering variables"); +} diff --git a/mysql-test/suite/rpl/r/rpl_change_master_find_log_pos_err.result b/mysql-test/suite/rpl/r/rpl_change_master_find_log_pos_err.result new file mode 100644 index 00000000000..0ff76b5b60f --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_change_master_find_log_pos_err.result @@ -0,0 +1,43 @@ +include/master-slave.inc +[connection master] +# +# Failed CHANGE MASTER TO should not change relay log status +# +connection slave; +include/stop_slave.inc +SET @@debug_dbug="d,simulate_find_log_pos_error"; +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=SLAVE_POS; +ERROR HY000: Target log not found in binlog index +SET @@debug_dbug=""; +include/start_slave.inc +# +# Ensure relay log can be updated after a failed CHANGE MASTER +# +FLUSH RELAY LOGS; +include/wait_for_slave_param.inc [Relay_Log_File] +# +# Slave should continue to receive data from old master after failed +# CHANGE MASTER TO +# +connection master; +CREATE TABLE t1 (a int); +insert into t1 values (1); +connection slave; +connection slave; +# +# Future CHANGE MASTER calls should succeed +# +include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=SLAVE_POS; +include/start_slave.inc +######################## +# Cleanup +######################## +connection master; +DROP TABLE t1; +connection slave; +include/stop_slave.inc +RESET SLAVE ALL; +change master to master_port=MASTER_MYPORT, master_host='127.0.0.1', master_user='root'; +include/start_slave.inc +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_reset_slave_all_clears_filters.result b/mysql-test/suite/rpl/r/rpl_reset_slave_all_clears_filters.result new file mode 100644 index 00000000000..a273aeaa678 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_reset_slave_all_clears_filters.result @@ -0,0 +1,54 @@ +include/master-slave.inc +[connection master] +connection slave; +include/stop_slave.inc +# +# Category 1) DO_DOMAIN_IDS and IGNORE_SERVER_IDS specified together +# +# Id filtering variable values should be empty initially +# Set id filtering variables +CHANGE MASTER TO DO_DOMAIN_IDS=(1), IGNORE_DOMAIN_IDS=(), IGNORE_SERVER_IDS=(3), MASTER_USE_GTID=SLAVE_POS; +# do domain id list: 1 +# ignore domain id list: +# ignore server id list: 3 +# RESET SLAVE ALL should clear values for all id filtering variables +RESET SLAVE ALL; +change master to master_port=MASTER_MYPORT, master_host='127.0.0.1', master_user='root'; +include/start_slave.inc +include/stop_slave.inc +# +# Category 2) IGNORE_DOMAIN_IDS and IGNORE_SERVER_IDS specified together +# +# Id filtering variable values should be empty initially +# Set id filtering variables +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(2), IGNORE_SERVER_IDS=(3), MASTER_USE_GTID=SLAVE_POS; +# do domain id list: +# ignore domain id list: 2 +# ignore server id list: 3 +# RESET SLAVE ALL should clear values for all id filtering variables +RESET SLAVE ALL; +change master to master_port=MASTER_MYPORT, master_host='127.0.0.1', master_user='root'; +include/start_slave.inc +include/stop_slave.inc +# +# Category 3) Null check - edge case with all empty lists to ensure a +# lack of specification doesn't break anything +# +# Id filtering variable values should be empty initially +# Set id filtering variables +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(), IGNORE_SERVER_IDS=(), MASTER_USE_GTID=SLAVE_POS; +# do domain id list: +# ignore domain id list: +# ignore server id list: +# RESET SLAVE ALL should clear values for all id filtering variables +RESET SLAVE ALL; +change master to master_port=MASTER_MYPORT, master_host='127.0.0.1', master_user='root'; +include/start_slave.inc +include/stop_slave.inc +############################ +# Cleanup +############################ +connection slave; +change master to master_port=MASTER_MYPORT, master_host='127.0.0.1', master_user='root'; +include/start_slave.inc +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_change_master_find_log_pos_err.test b/mysql-test/suite/rpl/t/rpl_change_master_find_log_pos_err.test new file mode 100644 index 00000000000..d1c2c03f010 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_change_master_find_log_pos_err.test @@ -0,0 +1,93 @@ +# +# Purpose: +# This test ensures that issuing a CHANGE MASTER will not put a replica into +# an inconsistent state if the slave cannot find the log files (i.e. the call to +# find_log_pos in reset_logs fails). More specifically, right before a replica +# purges the relay logs (part of the `CHANGE MASTER TO` logic), the relay log is +# temporarily closed with state LOG_TO_BE_OPENED. If the server is issued a +# CHANGE MASTER and it errors in-between the temporary log closure and purge, +# i.e. during the function find_log_pos, the log should be closed. The bug +# reported by MDEV-25284 revealed the log is not properly closed, such that +# future relay log updates fail, and future CHANGE MASTER calls crash the +# server. +# +# Methodology: +# This test ensures that the relay log is properly closed by ensuring future +# updates and CHANGE MASTER calls succeed. +# +# References: +# MDEV-25284: Assertion `info->type == READ_CACHE || +# info->type == WRITE_CACHE' failed +# +--source include/master-slave.inc +--source include/have_debug.inc + +--echo # +--echo # Failed CHANGE MASTER TO should not change relay log status +--echo # + +--connection slave +--source include/stop_slave.inc +SET @@debug_dbug="d,simulate_find_log_pos_error"; +error 1373; +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=SLAVE_POS; +SET @@debug_dbug=""; +--source include/start_slave.inc + + +--echo # +--echo # Ensure relay log can be updated after a failed CHANGE MASTER +--echo # + +FLUSH RELAY LOGS; +--let $slave_param= Relay_Log_File +--let $slave_param_value= slave-relay-bin.000003 +--source include/wait_for_slave_param.inc + + +--echo # +--echo # Slave should continue to receive data from old master after failed +--echo # CHANGE MASTER TO +--echo # + +--connection master +CREATE TABLE t1 (a int); +insert into t1 values (1); +--let $master_checksum= `CHECKSUM TABLE t1` +--sync_slave_with_master + +--connection slave +if ($master_checksum != `CHECKSUM TABLE t1`) +{ + die("Replica failed to pull data from primary after failed CHANGE MASTER TO"); +} + + +--echo # +--echo # Future CHANGE MASTER calls should succeed +--echo # + +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=SLAVE_POS; +--source include/start_slave.inc + + +--echo ######################## +--echo # Cleanup +--echo ######################## + +--connection master +DROP TABLE t1; + +--connection slave +--source include/stop_slave.inc +RESET SLAVE ALL; +--replace_result $MASTER_MYPORT MASTER_MYPORT +eval change master to master_port=$MASTER_MYPORT, master_host='127.0.0.1', master_user='root'; +--source include/start_slave.inc + +--disable_query_log +call mtr.add_suppression("Failed to locate old binlog or relay log files"); +--enable_query_log + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_reset_slave_all_clears_filters.test b/mysql-test/suite/rpl/t/rpl_reset_slave_all_clears_filters.test new file mode 100644 index 00000000000..7c01ce16586 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_reset_slave_all_clears_filters.test @@ -0,0 +1,72 @@ +# +# Purpose: +# This test validates that after issuing the `SLAVE RESET ALL` command, +# any corresponding IGNORE_DOMAIN_IDS/DO_DOMAIN_IDS and IGNORE_SERVER_IDS +# values are cleared. +# +# +# Methodology: +# To ensure the filtering variables are properly cleared after issuing +# SLAVE RESET ALL, we categorize different combinations of allowable input +# into three different options, and ensure that the variables are cleared for +# each category. The categories are as follows: +# Category 1) DO_DOMAIN_IDS and IGNORE_SERVER_IDS specified together +# Category 2) IGNORE_DOMAIN_IDS and IGNORE_SERVER_IDS specified together +# Category 3) Null check - edge case with all empty lists to ensure a lack +# of specification doesn't break anything +# +# To specify the values, the variables are set in `CHANGE MASTER TO`. To +# ensure the slave state is correct, we test the domain/server id filtering +# variable values at the following times while testing each category. +# +# Before CHANGE MASTER TO the filtering variables are tested to all be +# empty. +# +# After CHANGE MASTER TO the variables are tested to ensure they reflect +# those set in the CHANGE MASTER command. +# +# After RESET SLAVE ALL the filtering variables are tested to all be +# empty. +# + +--source include/master-slave.inc +--source include/have_debug.inc + +--connection slave +--source include/stop_slave.inc + +--echo # +--echo # Category 1) DO_DOMAIN_IDS and IGNORE_SERVER_IDS specified together +--echo # +--let $_do_domain_ids= (1) +--let $_ignore_domain_ids= () +--let $_ignore_server_ids= (3) +--source include/rpl_reset_slave_all_check.inc + +--echo # +--echo # Category 2) IGNORE_DOMAIN_IDS and IGNORE_SERVER_IDS specified together +--echo # +--let $_do_domain_ids= () +--let $_ignore_domain_ids= (2) +--let $_ignore_server_ids= (3) +--source include/rpl_reset_slave_all_check.inc + +--echo # +--echo # Category 3) Null check - edge case with all empty lists to ensure a +--echo # lack of specification doesn't break anything +--echo # +--let $_do_domain_ids= () +--let $_ignore_domain_ids= () +--let $_ignore_server_ids= () +--source include/rpl_reset_slave_all_check.inc + + +--echo ############################ +--echo # Cleanup +--echo ############################ +--connection slave +--replace_result $MASTER_MYPORT MASTER_MYPORT +eval change master to master_port=$MASTER_MYPORT, master_host='127.0.0.1', master_user='root'; +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/sql/item.cc b/sql/item.cc index 19acb594979..c79e706d875 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3950,8 +3950,48 @@ void Item_string::print(String *str, enum_query_type query_type) } else { - // Caller wants a result in the charset of str_value. - str_value.print(str); + /* + We're restoring a parse-able statement from an Item tree. + Make sure to revert character set conversions that previously + happened in the parser when Item_string was created. + */ + if (print_introducer) + { + /* + Print the string as is, without conversion: + Strings with introducers are not converted in the parser. + */ + str_value.print(str); + } + else + { + /* + Print the string with conversion. + Strings without introducers are converted in the parser, + from character_set_client to character_set_connection. + + When restoring a CREATE VIEW statement, + - str_value.charsets() contains parse time character_set_connection + - str->charset() contains parse time character_set_client + So we convert the string back from parse-time character_set_connection + to parse time character_set_client. + + In some cases, e.g. SHOW PROCEDURE CODE, it's also possible + that str->charset() is "utf8mb3" instead of parse time + character_set_client. In these cases we convert + here from the parse-time character_set_connection to utf8mb3. + + QQ: perhaps the code behind SHOW PROCEDURE CODE should + also request the result in the parse-time character_set_client + (like the code restoring CREATE VIEW statements does), + rather than in utf8mb3: + - utf8mb3 does not work well with non-BMP characters (e.g. emoji). + - Simply changing utf8mb3 to utf8mb4 will not fully help: + some character sets have unassigned characters, + they get lost during during cs->utf8mb4->cs round trip. + */ + str_value.print_with_conversion(str, str->charset()); + } } str->append('\''); diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 082d7935360..51e8825aca8 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -3537,6 +3537,7 @@ const char *Item_func_json_format::func_name() const bool Item_func_json_format::fix_length_and_dec() { decimals= 0; + collation.set(args[0]->collation); max_length= args[0]->max_length; maybe_null= 1; return FALSE; diff --git a/sql/log.h b/sql/log.h index b3b598e08ea..d923356f8d9 100644 --- a/sql/log.h +++ b/sql/log.h @@ -939,6 +939,20 @@ public: void unlock_binlog_end_pos() { mysql_mutex_unlock(&LOCK_binlog_end_pos); } mysql_mutex_t* get_binlog_end_pos_lock() { return &LOCK_binlog_end_pos; } + /* + Ensures the log's state is either LOG_OPEN or LOG_CLOSED. If something + failed along the desired path and left the log in invalid state, i.e. + LOG_TO_BE_OPENED, forces the state to be LOG_CLOSED. + */ + void try_fix_log_state() + { + mysql_mutex_lock(get_log_lock()); + /* Only change the log state if it is LOG_TO_BE_OPENED */ + if (log_state == LOG_TO_BE_OPENED) + log_state= LOG_CLOSED; + mysql_mutex_unlock(get_log_lock()); + } + int wait_for_update_binlog_end_pos(THD* thd, struct timespec * timeout); /* diff --git a/sql/log_event.cc b/sql/log_event.cc index c82a721708b..947ee3f7707 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. - Copyright (c) 2009, 2020, MariaDB + Copyright (c) 2009, 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 @@ -11716,19 +11716,21 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) restore_empty_query_table_list(thd->lex); #if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE) - if (WSREP(thd) && thd->wsrep_exec_mode == REPL_RECV) - { - query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock); - } + if (WSREP(thd) && thd->wsrep_exec_mode == REPL_RECV) + query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock); #endif /* WITH_WSREP && HAVE_QUERY_CACHE */ - if (unlikely(get_flags(STMT_END_F) && - (error= rows_event_stmt_cleanup(rgi, thd)))) - slave_rows_error_report(ERROR_LEVEL, - thd->is_error() ? 0 : error, - rgi, thd, table, - get_type_str(), - RPL_LOG_NAME, log_pos); + if (get_flags(STMT_END_F)) + { + if (unlikely(error= rows_event_stmt_cleanup(rgi, thd))) + slave_rows_error_report(ERROR_LEVEL, + thd->is_error() ? 0 : error, + rgi, thd, table, + get_type_str(), + RPL_LOG_NAME, log_pos); + if (thd->slave_thread) + free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC)); + } DBUG_RETURN(error); err: diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 87bb995ba9a..87294bcd11a 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -170,6 +170,8 @@ void Master_info::clear_in_memory_info(bool all) { port= MYSQL_PORT; host[0] = 0; user[0] = 0; password[0] = 0; + domain_id_filter.clear_ids(); + reset_dynamic(&ignore_server_ids); } } @@ -1793,6 +1795,12 @@ void Domain_id_filter::reset_filter() m_filter= false; } +void Domain_id_filter::clear_ids() +{ + reset_dynamic(&m_domain_ids[DO_DOMAIN_IDS]); + reset_dynamic(&m_domain_ids[IGNORE_DOMAIN_IDS]); +} + /** Update the do/ignore domain id filter lists. diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index 308d5af6f16..d7a61639b67 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -79,6 +79,11 @@ public: void reset_filter(); /* + Clear do_ids and ignore_ids to disable domain id filtering + */ + void clear_ids(); + + /* Update the do/ignore domain id filter lists. @param do_ids [IN] domain ids to be kept diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 848b37fec62..4c68b4505a4 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -9624,8 +9624,8 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, LEX_USER *user_from, LEX_USER *user_to) { int result= 0; - int idx; int elements; + bool restart; const char *UNINIT_VAR(user); const char *UNINIT_VAR(host); ACL_USER *acl_user= NULL; @@ -9734,84 +9734,100 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, DBUG_RETURN(-1); } + #ifdef EXTRA_DEBUG DBUG_PRINT("loop",("scan struct: %u search user: '%s' host: '%s'", struct_no, user_from->user.str, user_from->host.str)); #endif - /* Loop over all elements *backwards* (see the comment below). */ - for (idx= elements - 1; idx >= 0; idx--) - { - /* - Get a pointer to the element. - */ - switch (struct_no) { - case USER_ACL: - acl_user= dynamic_element(&acl_users, idx, ACL_USER*); - user= acl_user->user.str; - host= acl_user->host.hostname; - break; + /* Loop over elements backwards as it may reduce the number of mem-moves + for dynamic arrays. - case DB_ACL: - acl_db= &acl_dbs.at(idx); - user= acl_db->user; - host= acl_db->host.hostname; + We restart the loop, if we deleted or updated anything in a hash table + because calling my_hash_delete or my_hash_update shuffles elements indices + and we can miss some if we do only one scan. + */ + do { + restart= false; + for (int idx= elements - 1; idx >= 0; idx--) + { + /* + Get a pointer to the element. + */ + switch (struct_no) { + case USER_ACL: + acl_user= dynamic_element(&acl_users, idx, ACL_USER*); + user= acl_user->user.str; + host= acl_user->host.hostname; break; - case COLUMN_PRIVILEGES_HASH: - case PROC_PRIVILEGES_HASH: - case FUNC_PRIVILEGES_HASH: - case PACKAGE_SPEC_PRIVILEGES_HASH: - case PACKAGE_BODY_PRIVILEGES_HASH: - grant_name= (GRANT_NAME*) my_hash_element(grant_name_hash, idx); - user= grant_name->user; - host= grant_name->host.hostname; - break; + case DB_ACL: + acl_db= &acl_dbs.at(idx); + user= acl_db->user; + host= acl_db->host.hostname; + break; - case PROXY_USERS_ACL: - acl_proxy_user= dynamic_element(&acl_proxy_users, idx, ACL_PROXY_USER*); - user= acl_proxy_user->get_user(); - host= acl_proxy_user->get_host(); - break; + case COLUMN_PRIVILEGES_HASH: + case PROC_PRIVILEGES_HASH: + case FUNC_PRIVILEGES_HASH: + case PACKAGE_SPEC_PRIVILEGES_HASH: + case PACKAGE_BODY_PRIVILEGES_HASH: + grant_name= (GRANT_NAME*) my_hash_element(grant_name_hash, idx); + user= grant_name->user; + host= grant_name->host.hostname; + break; - case ROLES_MAPPINGS_HASH: - role_grant_pair= (ROLE_GRANT_PAIR *) my_hash_element(roles_mappings_hash, idx); - user= role_grant_pair->u_uname; - host= role_grant_pair->u_hname; - break; + case PROXY_USERS_ACL: + acl_proxy_user= dynamic_element(&acl_proxy_users, idx, ACL_PROXY_USER*); + user= acl_proxy_user->get_user(); + host= acl_proxy_user->get_host(); + break; - default: - DBUG_ASSERT(0); - } - if (! user) - user= ""; - if (! host) - host= ""; + case ROLES_MAPPINGS_HASH: + role_grant_pair= (ROLE_GRANT_PAIR *) my_hash_element(roles_mappings_hash, idx); + user= role_grant_pair->u_uname; + host= role_grant_pair->u_hname; + break; + + default: + DBUG_ASSERT(0); + } + if (! user) + user= ""; + if (! host) + host= ""; #ifdef EXTRA_DEBUG - DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'", - struct_no, idx, user, host)); + DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'", + struct_no, idx, user, host)); #endif - if (struct_no == ROLES_MAPPINGS_HASH) - { - const char* role= role_grant_pair->r_uname? role_grant_pair->r_uname: ""; - if (user_from->is_role()) + if (struct_no == ROLES_MAPPINGS_HASH) { - /* When searching for roles within the ROLES_MAPPINGS_HASH, we have - to check both the user field as well as the role field for a match. + const char* role= role_grant_pair->r_uname? role_grant_pair->r_uname: ""; + if (user_from->is_role()) + { + /* When searching for roles within the ROLES_MAPPINGS_HASH, we have + to check both the user field as well as the role field for a match. - It is possible to have a role granted to a role. If we are going - to modify the mapping entry, it needs to be done on either on the - "user" end (here represented by a role) or the "role" end. At least - one part must match. + It is possible to have a role granted to a role. If we are going + to modify the mapping entry, it needs to be done on either on the + "user" end (here represented by a role) or the "role" end. At least + one part must match. - If the "user" end has a not-empty host string, it can never match - as we are searching for a role here. A role always has an empty host - string. - */ - if ((*host || strcmp(user_from->user.str, user)) && - strcmp(user_from->user.str, role)) - continue; + If the "user" end has a not-empty host string, it can never match + as we are searching for a role here. A role always has an empty host + string. + */ + if ((*host || strcmp(user_from->user.str, user)) && + strcmp(user_from->user.str, role)) + continue; + } + else + { + if (strcmp(user_from->user.str, user) || + my_strcasecmp(system_charset_info, user_from->host.str, host)) + continue; + } } else { @@ -9819,158 +9835,135 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, my_strcasecmp(system_charset_info, user_from->host.str, host)) continue; } - } - else - { - if (strcmp(user_from->user.str, user) || - my_strcasecmp(system_charset_info, user_from->host.str, host)) - continue; - } - result= 1; /* At least one element found. */ - if ( drop ) - { - elements--; - switch ( struct_no ) { - case USER_ACL: - free_acl_user(dynamic_element(&acl_users, idx, ACL_USER*)); - delete_dynamic_element(&acl_users, idx); - break; + result= 1; /* At least one element found. */ + if ( drop ) + { + elements--; + switch ( struct_no ) { + case USER_ACL: + free_acl_user(dynamic_element(&acl_users, idx, ACL_USER*)); + delete_dynamic_element(&acl_users, idx); + break; - case DB_ACL: - acl_dbs.del(idx); - break; + case DB_ACL: + acl_dbs.del(idx); + break; - case COLUMN_PRIVILEGES_HASH: - case PROC_PRIVILEGES_HASH: - case FUNC_PRIVILEGES_HASH: - case PACKAGE_SPEC_PRIVILEGES_HASH: - case PACKAGE_BODY_PRIVILEGES_HASH: - my_hash_delete(grant_name_hash, (uchar*) grant_name); - /* - In our HASH implementation on deletion one elements - is moved into a place where a deleted element was, - and the last element is moved into the empty space. - Thus we need to re-examine the current element, but - we don't have to restart the search from the beginning. - */ - if (idx != elements) - idx++; - break; + case COLUMN_PRIVILEGES_HASH: + case PROC_PRIVILEGES_HASH: + case FUNC_PRIVILEGES_HASH: + case PACKAGE_SPEC_PRIVILEGES_HASH: + case PACKAGE_BODY_PRIVILEGES_HASH: + my_hash_delete(grant_name_hash, (uchar*) grant_name); + restart= true; + break; - case PROXY_USERS_ACL: - delete_dynamic_element(&acl_proxy_users, idx); - break; + case PROXY_USERS_ACL: + delete_dynamic_element(&acl_proxy_users, idx); + break; - case ROLES_MAPPINGS_HASH: - my_hash_delete(roles_mappings_hash, (uchar*) role_grant_pair); - if (idx != elements) - idx++; - break; + case ROLES_MAPPINGS_HASH: + my_hash_delete(roles_mappings_hash, (uchar*) role_grant_pair); + restart= true; + break; - default: - DBUG_ASSERT(0); - break; + default: + DBUG_ASSERT(0); + break; + } } - } - else if ( user_to ) - { - switch ( struct_no ) { - case USER_ACL: - acl_user->user.str= strdup_root(&acl_memroot, user_to->user.str); - acl_user->user.length= user_to->user.length; - update_hostname(&acl_user->host, strdup_root(&acl_memroot, user_to->host.str)); - acl_user->hostname_length= strlen(acl_user->host.hostname); - break; + else if ( user_to ) + { + switch ( struct_no ) { + case USER_ACL: + acl_user->user.str= strdup_root(&acl_memroot, user_to->user.str); + acl_user->user.length= user_to->user.length; + update_hostname(&acl_user->host, strdup_root(&acl_memroot, user_to->host.str)); + acl_user->hostname_length= strlen(acl_user->host.hostname); + break; - case DB_ACL: - acl_db->user= strdup_root(&acl_memroot, user_to->user.str); - update_hostname(&acl_db->host, strdup_root(&acl_memroot, user_to->host.str)); - break; + case DB_ACL: + acl_db->user= strdup_root(&acl_memroot, user_to->user.str); + update_hostname(&acl_db->host, strdup_root(&acl_memroot, user_to->host.str)); + break; - case COLUMN_PRIVILEGES_HASH: - case PROC_PRIVILEGES_HASH: - case FUNC_PRIVILEGES_HASH: - case PACKAGE_SPEC_PRIVILEGES_HASH: - case PACKAGE_BODY_PRIVILEGES_HASH: - { - /* - Save old hash key and its length to be able to properly update - element position in hash. - */ - char *old_key= grant_name->hash_key; - size_t old_key_length= grant_name->key_length; + case COLUMN_PRIVILEGES_HASH: + case PROC_PRIVILEGES_HASH: + case FUNC_PRIVILEGES_HASH: + case PACKAGE_SPEC_PRIVILEGES_HASH: + case PACKAGE_BODY_PRIVILEGES_HASH: + { + /* + Save old hash key and its length to be able to properly update + element position in hash. + */ + char *old_key= grant_name->hash_key; + size_t old_key_length= grant_name->key_length; + + /* + Update the grant structure with the new user name and host name. + */ + grant_name->set_user_details(user_to->host.str, grant_name->db, + user_to->user.str, grant_name->tname, + TRUE); + + /* + Since username is part of the hash key, when the user name + is renamed, the hash key is changed. Update the hash to + ensure that the position matches the new hash key value + */ + my_hash_update(grant_name_hash, (uchar*) grant_name, (uchar*) old_key, + old_key_length); + restart= true; + break; + } - /* - Update the grant structure with the new user name and host name. - */ - grant_name->set_user_details(user_to->host.str, grant_name->db, - user_to->user.str, grant_name->tname, - TRUE); - - /* - Since username is part of the hash key, when the user name - is renamed, the hash key is changed. Update the hash to - ensure that the position matches the new hash key value - */ - my_hash_update(grant_name_hash, (uchar*) grant_name, (uchar*) old_key, - old_key_length); - /* - hash_update() operation could have moved element from the tail or - the head of the hash to the current position. But it can never - move an element from the head to the tail or from the tail to the - head over the current element. - So we need to examine the current element once again, but - we don't need to restart the search from the beginning. - */ - idx++; + case PROXY_USERS_ACL: + acl_proxy_user->set_user (&acl_memroot, user_to->user.str); + acl_proxy_user->set_host (&acl_memroot, user_to->host.str); break; - } - case PROXY_USERS_ACL: - acl_proxy_user->set_user (&acl_memroot, user_to->user.str); - acl_proxy_user->set_host (&acl_memroot, user_to->host.str); - break; + case ROLES_MAPPINGS_HASH: + { + /* + Save old hash key and its length to be able to properly update + element position in hash. + */ + char *old_key= role_grant_pair->hashkey.str; + size_t old_key_length= role_grant_pair->hashkey.length; + bool oom; + + if (user_to->is_role()) + oom= role_grant_pair->init(&acl_memroot, role_grant_pair->u_uname, + role_grant_pair->u_hname, + user_to->user.str, false); + else + oom= role_grant_pair->init(&acl_memroot, user_to->user.str, + user_to->host.str, + role_grant_pair->r_uname, false); + if (oom) + DBUG_RETURN(-1); + + my_hash_update(roles_mappings_hash, (uchar*) role_grant_pair, + (uchar*) old_key, old_key_length); + restart= true; + break; + } - case ROLES_MAPPINGS_HASH: - { - /* - Save old hash key and its length to be able to properly update - element position in hash. - */ - char *old_key= role_grant_pair->hashkey.str; - size_t old_key_length= role_grant_pair->hashkey.length; - bool oom; - - if (user_to->is_role()) - oom= role_grant_pair->init(&acl_memroot, role_grant_pair->u_uname, - role_grant_pair->u_hname, - user_to->user.str, false); - else - oom= role_grant_pair->init(&acl_memroot, user_to->user.str, - user_to->host.str, - role_grant_pair->r_uname, false); - if (oom) - DBUG_RETURN(-1); - - my_hash_update(roles_mappings_hash, (uchar*) role_grant_pair, - (uchar*) old_key, old_key_length); - idx++; // see the comment above + default: + DBUG_ASSERT(0); break; } - default: - DBUG_ASSERT(0); + } + else + { + /* If search is requested, we do not need to search further. */ break; } - } - else - { - /* If search is requested, we do not need to search further. */ - break; - } - } + } while (restart); #ifdef EXTRA_DEBUG DBUG_PRINT("loop",("scan struct: %u result %d", struct_no, result)); #endif diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 967b85496ac..3475b622130 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -785,6 +785,9 @@ retry: if (!(handler= mysql_ha_find_handler(thd, &tables->alias))) goto err0; + if (thd->transaction.xid_state.check_has_uncommitted_xa()) + goto err0; + table= handler->table; tables->table= table; // This is used by fix_fields table->pos_in_table_list= tables; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 389346e389d..7d1ddc08aaa 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -3882,6 +3882,16 @@ err: mi->unlock_slave_threads(); if (ret == FALSE) my_ok(thd); + else + { + /* + Depending on where CHANGE MASTER failed, the logs may be waiting to be + reopened. This would break future log updates and CHANGE MASTER calls. + `try_fix_log_state()` allows the relay log to fix its state to no longer + expect to be reopened. + */ + mi->rli.relay_log.try_fix_log_state(); + } DBUG_RETURN(ret); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c943de11394..fe02e7b44e4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -26867,6 +26867,11 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) //Item List bool first= 1; + /* + outer_select() can not be used here because it is for name resolution + and will return NULL at any end of name resolution chain (view/derived) + */ + bool top_level= (get_master()->get_master() == 0); List_iterator_fast<Item> it(item_list); Item *item; while ((item= it++)) @@ -26876,7 +26881,8 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) else str->append(','); - if (is_subquery_function() && item->is_autogenerated_name) + if ((is_subquery_function() && item->is_autogenerated_name) || + !item->name.str) { /* Do not print auto-generated aliases in subqueries. It has no purpose @@ -26885,7 +26891,20 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) item->print(str, query_type); } else - item->print_item_w_name(str, query_type); + { + /* + Do not print illegal names (if it is not top level SELECT). + Top level view checked (and correct name are assigned), + other cases of top level SELECT are not important, because + it is not "table field". + */ + if (top_level || + !item->is_autogenerated_name || + !check_column_name(item->name.str)) + item->print_item_w_name(str, query_type); + else + item->print(str, query_type); + } } /* diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5a3c27832ac..b2f9fdf87fe 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4474,7 +4474,9 @@ make_table_name_list(THD *thd, Dynamic_array<LEX_CSTRING*> *table_names, if (!lookup_field_vals->wild_table_value && lookup_field_vals->table_value.str) { - if (lookup_field_vals->table_value.length > NAME_LEN) + if (check_table_name(lookup_field_vals->table_value.str, + lookup_field_vals->table_value.length, + false)) { /* Impossible value for a table name, @@ -4511,6 +4513,9 @@ make_table_name_list(THD *thd, Dynamic_array<LEX_CSTRING*> *table_names, return (schema_tables_add(thd, table_names, lookup_field_vals->table_value.str)); + if (check_db_name((LEX_STRING*)db_name)) + return 0; // Impossible TABLE_SCHEMA name + find_files_result res= find_files(thd, table_names, db_name, path, &lookup_field_vals->table_value); if (res != FIND_FILES_OK) diff --git a/sql/table.cc b/sql/table.cc index e4501870a2b..ccc336962b6 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4298,6 +4298,21 @@ bool check_table_name(const char *name, size_t length, bool check_for_path_chars if (check_for_path_chars && (*name == '/' || *name == '\\' || *name == '~' || *name == FN_EXTCHAR)) return 1; + /* + We don't allow zero byte in table/schema names: + - Some code still uses NULL-terminated strings. + Zero bytes will confuse this code. + - There is a little practical use of zero bytes in names anyway. + Note, if the string passed as "name" comes here + from the parser as an identifier, it does not contain zero bytes, + as the parser rejects zero bytes in identifiers. + But "name" can also come here from queries like this: + SELECT * FROM I_S.TABLES WHERE TABLE_NAME='str'; + In this case "name" is a general string expression + and it can have any arbitrary bytes, including zero bytes. + */ + if (*name == 0x00) + return 1; name++; name_length++; } diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index 70d4604b5d2..a7f2fd99f02 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -195,3 +195,7 @@ ENDIF() IF(NOT (PLUGIN_INNOBASE STREQUAL DYNAMIC)) ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/extra/mariabackup ${CMAKE_BINARY_DIR}/extra/mariabackup) ENDIF() + +IF(WITH_UNIT_TESTS) + ADD_SUBDIRECTORY(unittest) +ENDIF() diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index cfbc257ef90..c9d8eb4375c 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -32,7 +32,7 @@ Full Text Search interface #include "fts0priv.h" #include "fts0types.h" #include "fts0types.ic" -#include "fts0vlc.ic" +#include "fts0vlc.h" #include "fts0plugin.h" #include "dict0priv.h" #include "dict0stats.h" @@ -579,6 +579,7 @@ fts_cache_init( cache->sync_heap->arg = mem_heap_create(1024); cache->total_size = 0; + cache->total_size_at_sync = 0; mutex_enter((ib_mutex_t*) &cache->deleted_lock); cache->deleted_doc_ids = ib_vector_create( @@ -1246,7 +1247,7 @@ fts_cache_node_add_positions( ulint enc_len; ulint last_pos; byte* ptr_start; - ulint doc_id_delta; + doc_id_t doc_id_delta; #ifdef UNIV_DEBUG if (cache) { @@ -1257,7 +1258,7 @@ fts_cache_node_add_positions( ut_ad(doc_id >= node->last_doc_id); /* Calculate the space required to store the ilist. */ - doc_id_delta = (ulint)(doc_id - node->last_doc_id); + doc_id_delta = doc_id - node->last_doc_id; enc_len = fts_get_encoded_len(doc_id_delta); last_pos = 0; @@ -1306,14 +1307,14 @@ fts_cache_node_add_positions( ptr_start = ptr; /* Encode the new fragment. */ - ptr += fts_encode_int(doc_id_delta, ptr); + ptr = fts_encode_int(doc_id_delta, ptr); last_pos = 0; for (i = 0; i < ib_vector_size(positions); i++) { ulint pos = *(static_cast<ulint*>( ib_vector_get(positions, i))); - ptr += fts_encode_int(pos - last_pos, ptr); + ptr = fts_encode_int(pos - last_pos, ptr); last_pos = pos; } @@ -3546,11 +3547,14 @@ fts_add_doc_by_id( get_doc->index_cache, doc_id, doc.tokens); - bool need_sync = false; - if ((cache->total_size > fts_max_cache_size / 10 - || fts_need_sync) - && !cache->sync->in_progress) { - need_sync = true; + bool need_sync = !cache->sync->in_progress + && (fts_need_sync + || (cache->total_size + - cache->total_size_at_sync) + > fts_max_cache_size / 10); + if (need_sync) { + cache->total_size_at_sync = + cache->total_size; } rw_lock_x_unlock(&table->fts->cache->lock); diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index 893a98aa11e..0288377d4ea 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -36,6 +36,7 @@ Completed 2011/7/10 Sunny and Jimmy Yang #include "ut0list.h" #include "zlib.h" #include "fts0opt.h" +#include "fts0vlc.h" /** The FTS optimize thread's work queue. */ ib_wqueue_t* fts_optimize_wq; @@ -1116,7 +1117,7 @@ fts_optimize_encode_node( ulint pos_enc_len; doc_id_t doc_id_delta; dberr_t error = DB_SUCCESS; - byte* src = enc->src_ilist_ptr; + const byte* src = enc->src_ilist_ptr; if (node->first_doc_id == 0) { ut_a(node->last_doc_id == 0); @@ -1173,7 +1174,7 @@ fts_optimize_encode_node( /* Encode the doc id. Cast to ulint, the delta should be small and therefore no loss of precision. */ - dst += fts_encode_int((ulint) doc_id_delta, dst); + dst = fts_encode_int(doc_id_delta, dst); /* Copy the encoded pos array. */ memcpy(dst, src, pos_enc_len); @@ -1220,7 +1221,8 @@ fts_optimize_node( doc_id_t delta; doc_id_t del_doc_id = FTS_NULL_DOC_ID; - delta = fts_decode_vlc(&enc->src_ilist_ptr); + delta = fts_decode_vlc( + (const byte**)&enc->src_ilist_ptr); test_again: /* Check whether the doc id is in the delete list, if @@ -1248,7 +1250,7 @@ test_again: /* Skip the entries for this document. */ while (*enc->src_ilist_ptr) { - fts_decode_vlc(&enc->src_ilist_ptr); + fts_decode_vlc((const byte**)&enc->src_ilist_ptr); } /* Skip the end of word position marker. */ @@ -2640,6 +2642,9 @@ fts_optimize_request_sync_table( ib_wqueue_add(fts_optimize_wq, msg, msg->heap, true); + DBUG_EXECUTE_IF("fts_optimize_wq_count_check", + DBUG_ASSERT(fts_optimize_wq->length <= 1000);); + mutex_exit(&fts_optimize_wq->mutex); } diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc index 5047e99f4d7..01227a8df58 100644 --- a/storage/innobase/fts/fts0que.cc +++ b/storage/innobase/fts/fts0que.cc @@ -34,6 +34,7 @@ Completed 2011/7/10 Sunny and Jimmy Yang #include "fts0pars.h" #include "fts0types.h" #include "fts0plugin.h" +#include "fts0vlc.h" #include <iomanip> #include <vector> @@ -3224,7 +3225,7 @@ fts_query_filter_doc_ids( ulint len, /*!< in: doc id ilist size */ ibool calc_doc_count) /*!< in: whether to remember doc count */ { - byte* ptr = static_cast<byte*>(data); + const byte* ptr = static_cast<byte*>(data); doc_id_t doc_id = 0; ulint decoded = 0; ib_rbt_t* doc_freqs = word_freq->doc_freqs; @@ -3234,8 +3235,8 @@ fts_query_filter_doc_ids( ulint freq = 0; fts_doc_freq_t* doc_freq; fts_match_t* match = NULL; - ulint last_pos = 0; - ulint pos = fts_decode_vlc(&ptr); + doc_id_t last_pos = 0; + doc_id_t pos = fts_decode_vlc(&ptr); /* Some sanity checks. */ if (doc_id == 0) { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 83da62591e3..d3138bbd6b9 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -8432,8 +8432,7 @@ calc_row_difference( && prebuilt->table->fts && innobase_strcasecmp( field->field_name.str, FTS_DOC_ID_COL_NAME) == 0) { - doc_id = (doc_id_t) mach_read_from_n_little_endian( - n_ptr, 8); + doc_id = mach_read_uint64_little_endian(n_ptr); if (doc_id == 0) { return(DB_FTS_INVALID_DOCID); } @@ -8674,16 +8673,6 @@ calc_row_difference( << innodb_table->name; return(DB_FTS_INVALID_DOCID); - } else if ((doc_id - - prebuilt->table->fts->cache->next_doc_id) - >= FTS_DOC_ID_MAX_STEP) { - - ib::warn() << "Doc ID " << doc_id << " is too" - " big. Its difference with largest" - " Doc ID used " << prebuilt->table->fts - ->cache->next_doc_id - 1 - << " cannot exceed or equal to " - << FTS_DOC_ID_MAX_STEP; } @@ -11852,10 +11841,6 @@ bool create_table_info_t::innobase_table_flags() ut_min(static_cast<ulint>(UNIV_PAGE_SSIZE_MAX), static_cast<ulint>(PAGE_ZIP_SSIZE_MAX)); - /* Cache the value of innobase_compression_level, in case it is - modified by another thread while the table is being created. */ - const ulint default_compression_level = page_zip_level; - ha_table_option_struct *options= m_form->s->option_struct; m_flags = 0; @@ -12044,12 +12029,23 @@ index_bad: m_flags2 |= DICT_TF2_USE_FILE_PER_TABLE; } + ulint level = ulint(options->page_compression_level); + if (!level) { + level = page_zip_level; + if (!level && options->page_compressed) { + push_warning_printf( + m_thd, Sql_condition::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: PAGE_COMPRESSED requires" + " PAGE_COMPRESSION_LEVEL or" + " innodb_compression_level > 0"); + DBUG_RETURN(false); + } + } + /* Set the table flags */ dict_tf_set(&m_flags, innodb_row_format, zip_ssize, - m_use_data_dir, - options->page_compressed, - options->page_compression_level == 0 ? - default_compression_level : ulint(options->page_compression_level)); + m_use_data_dir, options->page_compressed, level); if (m_form->s->table_type == TABLE_TYPE_SEQUENCE) { m_flags |= DICT_TF_MASK_NO_ROLLBACK; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 8418ad7316c..22af1f91f61 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -6473,6 +6473,8 @@ check_if_ok_to_rename: } if (!info.innobase_table_flags()) { + my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), + table_type(), "PAGE_COMPRESSED"); goto err_exit_no_heap; } diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 6d9ccae0b42..d80ed383675 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -58,6 +58,7 @@ Modified Dec 29, 2014 Jan Lindström (Added sys_semaphore_waits) #include "fil0fil.h" #include "fil0crypt.h" #include "dict0crea.h" +#include "fts0vlc.h" /** The latest successfully looked up innodb_fts_aux_table */ UNIV_INTERN table_id_t innodb_ft_aux_table_id; @@ -2759,7 +2760,7 @@ i_s_fts_index_cache_fill_one_index( /* Decrypt the ilist, and display Dod ID and word position */ for (ulint i = 0; i < ib_vector_size(word->nodes); i++) { fts_node_t* node; - byte* ptr; + const byte* ptr; ulint decoded = 0; doc_id_t doc_id = 0; @@ -2769,13 +2770,11 @@ i_s_fts_index_cache_fill_one_index( ptr = node->ilist; while (decoded < node->ilist_size) { - ulint pos = fts_decode_vlc(&ptr); - doc_id += pos; + doc_id += fts_decode_vlc(&ptr); /* Get position info */ while (*ptr) { - pos = fts_decode_vlc(&ptr); OK(field_store_string( fields[I_S_FTS_WORD], @@ -2796,7 +2795,7 @@ i_s_fts_index_cache_fill_one_index( doc_id, true)); OK(fields[I_S_FTS_ILIST_DOC_POS]->store( - pos, true)); + fts_decode_vlc(&ptr), true)); OK(schema_table_store_record( thd, table)); @@ -3130,7 +3129,7 @@ i_s_fts_index_table_fill_one_fetch( /* Decrypt the ilist, and display Dod ID and word position */ for (ulint i = 0; i < ib_vector_size(word->nodes); i++) { fts_node_t* node; - byte* ptr; + const byte* ptr; ulint decoded = 0; doc_id_t doc_id = 0; @@ -3140,13 +3139,10 @@ i_s_fts_index_table_fill_one_fetch( ptr = node->ilist; while (decoded < node->ilist_size) { - ulint pos = fts_decode_vlc(&ptr); - - doc_id += pos; + doc_id += fts_decode_vlc(&ptr); /* Get position info */ while (*ptr) { - pos = fts_decode_vlc(&ptr); OK(field_store_string( fields[I_S_FTS_WORD], @@ -3165,7 +3161,7 @@ i_s_fts_index_table_fill_one_fetch( longlong(doc_id), true)); OK(fields[I_S_FTS_ILIST_DOC_POS]->store( - pos, true)); + fts_decode_vlc(&ptr), true)); OK(schema_table_store_record( thd, table)); diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h index 9f5b83e7d2e..0b4712c7389 100644 --- a/storage/innobase/include/fts0fts.h +++ b/storage/innobase/include/fts0fts.h @@ -96,10 +96,6 @@ those defined in mysql file ft_global.h */ /** Threshold where our optimize thread automatically kicks in */ #define FTS_OPTIMIZE_THRESHOLD 10000000 -/** Threshold to avoid exhausting of doc ids. Consecutive doc id difference -should not exceed FTS_DOC_ID_MAX_STEP */ -#define FTS_DOC_ID_MAX_STEP 65535 - /** Maximum possible Fulltext word length in bytes (assuming mbmaxlen=4) */ #define FTS_MAX_WORD_LEN (HA_FT_MAXCHARLEN * 4) diff --git a/storage/innobase/include/fts0types.h b/storage/innobase/include/fts0types.h index f5760a16c0e..d49bc7c0254 100644 --- a/storage/innobase/include/fts0types.h +++ b/storage/innobase/include/fts0types.h @@ -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 @@ -150,6 +150,9 @@ struct fts_cache_t { size_t total_size; /*!< total size consumed by the ilist field of all nodes. SYNC is run whenever this gets too big */ + /** total_size at the time of the previous SYNC request */ + size_t total_size_at_sync; + fts_sync_t* sync; /*!< sync structure to sync data to disk */ ib_alloc_t* sync_heap; /*!< The heap allocator, for indexes @@ -315,16 +318,6 @@ int fts_doc_id_cmp( const void* p2); /*!< in: id2 */ /******************************************************************//** -Decode and return the integer that was encoded using our VLC scheme.*/ -UNIV_INLINE -ulint -fts_decode_vlc( -/*===========*/ - /*!< out: value decoded */ - byte** ptr); /*!< in: ptr to decode from, this ptr is - incremented by the number of bytes decoded */ - -/******************************************************************//** Duplicate a string. */ UNIV_INLINE void @@ -339,28 +332,6 @@ fts_string_dup( mem_heap_t* heap); /*!< in: heap to use */ /******************************************************************//** -Return length of val if it were encoded using our VLC scheme. */ -UNIV_INLINE -ulint -fts_get_encoded_len( -/*================*/ - /*!< out: length of value - encoded, in bytes */ - ulint val); /*!< in: value to encode */ - -/******************************************************************//** -Encode an integer using our VLC scheme and return the length in bytes. */ -UNIV_INLINE -ulint -fts_encode_int( -/*===========*/ - /*!< out: length of value - encoded, in bytes */ - ulint val, /*!< in: value to encode */ - byte* buf); /*!< in: buffer, must have - enough space */ - -/******************************************************************//** Get the selected FTS aux INDEX suffix. */ UNIV_INLINE const char* @@ -381,6 +352,5 @@ fts_select_index( ulint len); #include "fts0types.ic" -#include "fts0vlc.ic" #endif /* INNOBASE_FTS0TYPES_H */ diff --git a/storage/innobase/include/fts0vlc.h b/storage/innobase/include/fts0vlc.h new file mode 100644 index 00000000000..d6e6037777e --- /dev/null +++ b/storage/innobase/include/fts0vlc.h @@ -0,0 +1,124 @@ +/** + +Copyright (c) 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 +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA +**/ +/** +@file include/fts0vlc.h +Full text variable length integer encoding/decoding. + +Created 2021-10-19 Thirunarayanan Balathandayuthapani +**/ + +/** Return length of val if it were encoded using our VLC scheme. +@param val value to encode +@return length of value encoded, in bytes */ +inline size_t fts_get_encoded_len(doc_id_t val) +{ + if (val < static_cast<doc_id_t>(1) << 7) + return 1; + if (val < static_cast<doc_id_t>(1) << 14) + return 2; + if (val < static_cast<doc_id_t>(1) << 21) + return 3; + if (val < static_cast<doc_id_t>(1) << 28) + return 4; + if (val < static_cast<doc_id_t>(1) << 35) + return 5; + if (val < static_cast<doc_id_t>(1) << 42) + return 6; + if (val < static_cast<doc_id_t>(1) << 49) + return 7; + if (val < static_cast<doc_id_t>(1) << 56) + return 8; + if (val < static_cast<doc_id_t>(1) << 63) + return 9; + return 10; +} + +/** Encode an integer using our VLC scheme and return the +length in bytes. +@param val value to encode +@param buf buffer, must have enough space +@return length of value encoded, in bytes */ +inline byte *fts_encode_int(doc_id_t val, byte *buf) +{ + if (val < static_cast<doc_id_t>(1) << 7) + goto add_1; + if (val < static_cast<doc_id_t>(1) << 14) + goto add_2; + if (val < static_cast<doc_id_t>(1) << 21) + goto add_3; + if (val < static_cast<doc_id_t>(1) << 28) + goto add_4; + if (val < static_cast<doc_id_t>(1) << 35) + goto add_5; + if (val < static_cast<doc_id_t>(1) << 42) + goto add_6; + if (val < static_cast<doc_id_t>(1) << 49) + goto add_7; + if (val < static_cast<doc_id_t>(1) << 56) + goto add_8; + if (val < static_cast<doc_id_t>(1) << 63) + goto add_9; + + *buf++= static_cast<byte>(val >> 63); +add_9: + *buf++= static_cast<byte>(val >> 56) & 0x7F; +add_8: + *buf++= static_cast<byte>(val >> 49) & 0x7F; +add_7: + *buf++= static_cast<byte>(val >> 42) & 0x7F; +add_6: + *buf++= static_cast<byte>(val >> 35) & 0x7F; +add_5: + *buf++= static_cast<byte>(val >> 28) & 0x7F; +add_4: + *buf++= static_cast<byte>(val >> 21) & 0x7F; +add_3: + *buf++= static_cast<byte>(val >> 14) & 0x7F; +add_2: + *buf++= static_cast<byte>(val >> 7) & 0x7F; +add_1: + *buf++= static_cast<byte>(val) | 0x80; + return buf; +} + +/** Decode and return the integer that was encoded using +our VLC scheme. +@param ptr pointer to decode from, this ptr is + incremented by the number of bytes decoded +@return value decoded */ +inline doc_id_t fts_decode_vlc(const byte **ptr) +{ + ut_d(const byte *const start= *ptr); + ut_ad(*start); + + doc_id_t val= 0; + for (;;) + { + byte b= *(*ptr)++; + val|= (b & 0x7F); + + /* High-bit on means "last byte in the encoded integer". */ + if (b & 0x80) + break; + ut_ad(val < static_cast<doc_id_t>(1) << (64 - 7)); + val <<= 7; + } + + ut_ad(*ptr - start <= 10); + + return(val); +} diff --git a/storage/innobase/include/fts0vlc.ic b/storage/innobase/include/fts0vlc.ic deleted file mode 100644 index 75d8535057e..00000000000 --- a/storage/innobase/include/fts0vlc.ic +++ /dev/null @@ -1,142 +0,0 @@ -/***************************************************************************** - -Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved. - -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 -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/******************************************************************//** -@file include/fts0vlc.ic -Full text variable length integer encoding/decoding. - -Created 2007-03-27 Sunny Bains -*******************************************************/ - -#ifndef INNOBASE_FTS0VLC_IC -#define INNOBASE_FTS0VLC_IC - -#include "fts0types.h" - -/******************************************************************//** -Return length of val if it were encoded using our VLC scheme. -FIXME: We will need to be able encode 8 bytes value -@return length of value encoded, in bytes */ -UNIV_INLINE -ulint -fts_get_encoded_len( -/*================*/ - ulint val) /* in: value to encode */ -{ - if (val <= 127) { - return(1); - } else if (val <= 16383) { - return(2); - } else if (val <= 2097151) { - return(3); - } else if (val <= 268435455) { - return(4); - } else { - /* Possibly we should care that on 64-bit machines ulint can - contain values that we can't encode in 5 bytes, but - fts_encode_int doesn't handle them either so it doesn't much - matter. */ - - return(5); - } -} - -/******************************************************************//** -Encode an integer using our VLC scheme and return the length in bytes. -@return length of value encoded, in bytes */ -UNIV_INLINE -ulint -fts_encode_int( -/*===========*/ - ulint val, /* in: value to encode */ - byte* buf) /* in: buffer, must have enough space */ -{ - ulint len; - - if (val <= 127) { - *buf = (byte) val; - - len = 1; - } else if (val <= 16383) { - *buf++ = (byte)(val >> 7); - *buf = (byte)(val & 0x7F); - - len = 2; - } else if (val <= 2097151) { - *buf++ = (byte)(val >> 14); - *buf++ = (byte)((val >> 7) & 0x7F); - *buf = (byte)(val & 0x7F); - - len = 3; - } else if (val <= 268435455) { - *buf++ = (byte)(val >> 21); - *buf++ = (byte)((val >> 14) & 0x7F); - *buf++ = (byte)((val >> 7) & 0x7F); - *buf = (byte)(val & 0x7F); - - len = 4; - } else { - /* Best to keep the limitations of the 32/64 bit versions - identical, at least for the time being. */ - ut_ad(val <= 4294967295u); - - *buf++ = (byte)(val >> 28); - *buf++ = (byte)((val >> 21) & 0x7F); - *buf++ = (byte)((val >> 14) & 0x7F); - *buf++ = (byte)((val >> 7) & 0x7F); - *buf = (byte)(val & 0x7F); - - len = 5; - } - - /* High-bit on means "last byte in the encoded integer". */ - *buf |= 0x80; - - return(len); -} - -/******************************************************************//** -Decode and return the integer that was encoded using our VLC scheme. -@return value decoded */ -UNIV_INLINE -ulint -fts_decode_vlc( -/*===========*/ - byte** ptr) /* in: ptr to decode from, this ptr is - incremented by the number of bytes decoded */ -{ - ulint val = 0; - - for (;;) { - byte b = **ptr; - - ++*ptr; - val |= (b & 0x7F); - - /* High-bit on means "last byte in the encoded integer". */ - if (b & 0x80) { - break; - } else { - val <<= 7; - } - } - - return(val); -} - -#endif diff --git a/storage/innobase/include/mach0data.h b/storage/innobase/include/mach0data.h index 8141c8a91e0..860ef20b8bd 100644 --- a/storage/innobase/include/mach0data.h +++ b/storage/innobase/include/mach0data.h @@ -316,6 +316,28 @@ mach_read_from_n_little_endian( const byte* buf, /*!< in: from where to read */ ulint buf_size) /*!< in: from how many bytes to read */ MY_ATTRIBUTE((warn_unused_result)); + + +/** Reads a 64 bit stored in big endian format +@param buf From where to read +@return uint64_t */ +UNIV_INLINE +uint64_t +mach_read_uint64_little_endian(const byte* buf) +{ +#ifdef WORDS_BIGENDIAN + return + uint64_t(buf[0]) | uint64_t(buf[1]) << 8 | + uint64_t(buf[2]) << 16 | uint64_t(buf[3]) << 24 | + uint64_t(buf[4]) << 32 | uint64_t(buf[5]) << 40 | + uint64_t(buf[6]) << 48 | uint64_t(buf[7]) << 56; +#else + uint64_t n; + memcpy(&n, buf, sizeof(uint64_t)); + return n; +#endif +} + /*********************************************************//** Writes a ulint in the little-endian format. */ UNIV_INLINE diff --git a/storage/innobase/include/ut0wqueue.h b/storage/innobase/include/ut0wqueue.h index 5a895f4ea3c..d9cc7aec9c9 100644 --- a/storage/innobase/include/ut0wqueue.h +++ b/storage/innobase/include/ut0wqueue.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2006, 2014, 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 @@ -46,6 +46,8 @@ struct ib_wqueue_t ib_mutex_t mutex; /** Work item list */ ib_list_t* items; + /** ib_list_len(*items) */ + size_t length; /** event we use to signal additions to list; os_event_set() and os_event_reset() are protected by the mutex */ os_event_t event; @@ -103,12 +105,5 @@ void* ib_wqueue_nowait( /*=============*/ ib_wqueue_t* wq); /*<! in: work queue */ -/******************************************************************** -Get number of items on queue. -@return number of items on queue */ -ulint -ib_wqueue_len( -/*==========*/ - ib_wqueue_t* wq); /*<! in: work queue */ #endif /* IB_WORK_QUEUE_H */ diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 0b28fe03c41..e79264d3fb8 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1476,23 +1476,6 @@ error_exit: trx->error_state = DB_FTS_INVALID_DOCID; goto error_exit; } - - /* Difference between Doc IDs are restricted within - 4 bytes integer. See fts_get_encoded_len(). Consecutive - doc_ids difference should not exceed - FTS_DOC_ID_MAX_STEP value. */ - - if (doc_id - next_doc_id >= FTS_DOC_ID_MAX_STEP) { - ib::error() << "Doc ID " << doc_id - << " is too big. Its difference with" - " largest used Doc ID " - << next_doc_id - 1 << " cannot" - " exceed or equal to " - << FTS_DOC_ID_MAX_STEP; - err = DB_FTS_INVALID_DOCID; - trx->error_state = DB_FTS_INVALID_DOCID; - goto error_exit; - } } if (table->skip_alter_undo) { diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 298286899f1..b2cfbd9b4e3 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1352,13 +1352,6 @@ trx_commit_in_memory( ut_ad(!trx->rsegs.m_redo.undo); - if (trx_rseg_t* rseg = trx->rsegs.m_redo.rseg) { - mutex_enter(&rseg->mutex); - ut_ad(rseg->trx_ref_count > 0); - --rseg->trx_ref_count; - mutex_exit(&rseg->mutex); - } - if (mtr != NULL) { if (trx_undo_t*& undo = trx->rsegs.m_noredo.undo) { ut_ad(undo->rseg == trx->rsegs.m_noredo.rseg); @@ -1418,6 +1411,15 @@ trx_commit_in_memory( ut_ad(!trx->rsegs.m_noredo.undo); + /* Only after trx_undo_commit_cleanup() it is safe to release + our rseg reference. */ + if (trx_rseg_t* rseg = trx->rsegs.m_redo.rseg) { + mutex_enter(&rseg->mutex); + ut_ad(rseg->trx_ref_count > 0); + --rseg->trx_ref_count; + mutex_exit(&rseg->mutex); + } + /* Free all savepoints, starting from the first. */ trx_named_savept_t* savep = UT_LIST_GET_FIRST(trx->trx_savepoints); diff --git a/storage/innobase/unittest/CMakeLists.txt b/storage/innobase/unittest/CMakeLists.txt new file mode 100644 index 00000000000..df98cddf73e --- /dev/null +++ b/storage/innobase/unittest/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright (c) 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 Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/unittest/mytap + ${CMAKE_SOURCE_DIR}/storage/innobase/include) +ADD_EXECUTABLE(innodb_fts-t innodb_fts-t.cc) +TARGET_LINK_LIBRARIES(innodb_fts-t mysys mytap) +ADD_DEPENDENCIES(innodb_fts-t GenError) +MY_ADD_TEST(innodb_fts) diff --git a/storage/innobase/unittest/innodb_fts-t.cc b/storage/innobase/unittest/innodb_fts-t.cc new file mode 100644 index 00000000000..57585e337c2 --- /dev/null +++ b/storage/innobase/unittest/innodb_fts-t.cc @@ -0,0 +1,52 @@ +#include "tap.h" +#include "fts0fts.h" +#include "fts0vlc.h" + +struct fts_encode_info +{ + const byte buf[10]; + int32_t len; + doc_id_t val; +}; + +/* Contains fts encoding min & max value for each length bytes */ +static const fts_encode_info fts_info[]= +{ + {{0x80}, 1, 0}, + {{0xFF}, 1, (1 << 7) - 1}, + {{0x01, 0x80}, 2, 1 << 7}, + {{0x7F, 0XFF}, 2, (1 << 14) - 1}, + {{0x01, 0x00, 0x80}, 3, 1 << 14}, + {{0x7F, 0X7F, 0XFF}, 3, (1 << 21) - 1}, + {{0x01, 0x00, 0x00, 0x80}, 4, 1 << 21}, + {{0x7F, 0X7F, 0X7F, 0xFF}, 4, (1 << 28) - 1}, + {{0x01, 0x00, 0x00, 0x00, 0x80}, 5, 1 << 28}, + {{0x7F, 0X7F, 0X7F, 0x7F, 0xFF}, 5, (1ULL << 35) - 1}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x80}, 6, 1ULL << 35}, + {{0x7F, 0X7F, 0X7F, 0x7F, 0x7F, 0xFF}, 6, (1ULL << 42) - 1}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}, 7, 1ULL << 42}, + {{0x7F, 0X7F, 0X7F, 0x7F, 0x7F, 0x7F, 0XFF}, 7, (1ULL << 49) - 1}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}, 8, 1ULL << 49}, + {{0x7F, 0X7F, 0X7F, 0x7F, 0x7F, 0x7F, 0X7F, 0XFF}, 8, (1ULL << 56) -1}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}, 9, 1ULL << 56}, + {{0x7F, 0X7F, 0X7F, 0x7F, 0x7F, 0x7F, 0X7F, 0x7F, 0XFF}, 9, (1ULL << 63) -1}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}, 10, 1ULL << 63}, + {{0x01, 0X7F, 0X7F, 0x7F, 0x7F, 0x7F, 0X7F, 0x7F, 0x7F, 0xFF}, 10, ~0ULL} +}; + +int main(int, char**) +{ + for (int i= array_elements(fts_info); i--;) + { + byte buf[10]; + const byte* fts_buf= buf; + int32_t len= fts_encode_int(fts_info[i].val, buf) - &buf[0]; + if (fts_info[i].len == len && + !memcmp(&fts_info[i].buf, buf, len) && + fts_decode_vlc(&fts_buf) == fts_info[i].val && + fts_buf == &buf[len]) + ok(true, "FTS Encoded for %d bytes", fts_info[i].len); + else + ok(false, "FTS Encoded for %d bytes", fts_info[i].len); + } +} diff --git a/storage/innobase/ut/ut0wqueue.cc b/storage/innobase/ut/ut0wqueue.cc index ae97009430e..45af449cff9 100644 --- a/storage/innobase/ut/ut0wqueue.cc +++ b/storage/innobase/ut/ut0wqueue.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2006, 2015, 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 @@ -45,6 +45,7 @@ ib_wqueue_create(void) wq->items = ib_list_create(); wq->event = os_event_create(0); + wq->length = 0; return(wq); } @@ -76,6 +77,8 @@ ib_wqueue_add(ib_wqueue_t* wq, void* item, mem_heap_t* heap, bool wq_locked) } ib_list_add_last(wq->items, item, heap); + wq->length++; + ut_ad(wq->length == ib_list_len(wq->items)); os_event_set(wq->event); if (!wq_locked) { @@ -102,12 +105,12 @@ ib_wqueue_wait( if (node) { ib_list_remove(wq->items, node); - - if (!ib_list_get_first(wq->items)) { + if (!--wq->length) { /* We must reset the event when the list gets emptied. */ os_event_reset(wq->event); } + ut_ad(wq->length == ib_list_len(wq->items)); break; } @@ -142,7 +145,8 @@ ib_wqueue_timedwait( if (node) { ib_list_remove(wq->items, node); - + wq->length--; + ut_ad(wq->length == ib_list_len(wq->items)); mutex_exit(&wq->mutex); break; } @@ -204,20 +208,3 @@ bool ib_wqueue_is_empty(ib_wqueue_t* wq) mutex_exit(&wq->mutex); return is_empty; } - -/******************************************************************** -Get number of items on queue. -@return number of items on queue */ -ulint -ib_wqueue_len( -/*==========*/ - ib_wqueue_t* wq) /*<! in: work queue */ -{ - ulint len = 0; - - mutex_enter(&wq->mutex); - len = ib_list_len(wq->items); - mutex_exit(&wq->mutex); - - return(len); -} |