diff --git a/client/mysql.cc b/client/mysql.cc index ca7cb7dd910..22d9d84d582 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -606,7 +606,6 @@ static COMMANDS commands[] = { { "OLD_PASSWORD", 0, 0, 0, ""}, { "ON", 0, 0, 0, ""}, { "ONE", 0, 0, 0, ""}, - { "ONE_SHOT", 0, 0, 0, ""}, { "OPEN", 0, 0, 0, ""}, { "OPTIMIZE", 0, 0, 0, ""}, { "OPTION", 0, 0, 0, ""}, diff --git a/client/mysqldump.c b/client/mysqldump.c index a0222f370b3..b3a679261d7 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -4406,6 +4406,12 @@ static int dump_all_tables_in_db(char *database) else verbose_msg("-- dump_all_tables_in_db : logs flushed successfully!\n"); } + if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500) + { + verbose_msg("-- Setting savepoint...\n"); + if (mysql_query_with_error_report(mysql, 0, "SAVEPOINT sp")) + DBUG_RETURN(1); + } while ((table= getTableName(0))) { char *end= strmov(afterdot, table); @@ -4423,6 +4429,23 @@ static int dump_all_tables_in_db(char *database) maybe_exit(EX_MYSQLERR); } } + + /** + ROLLBACK TO SAVEPOINT in --single-transaction mode to release metadata + lock on table which was already dumped. This allows to avoid blocking + concurrent DDL on this table without sacrificing correctness, as we + won't access table second time and dumps created by --single-transaction + mode have validity point at the start of transaction anyway. + Note that this doesn't make --single-transaction mode with concurrent + DDL safe in general case. It just improves situation for people for whom + it might be working. + */ + if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500) + { + verbose_msg("-- Rolling back to savepoint sp...\n"); + if (mysql_query_with_error_report(mysql, 0, "ROLLBACK TO SAVEPOINT sp")) + maybe_exit(EX_MYSQLERR); + } } else { @@ -4445,6 +4468,14 @@ static int dump_all_tables_in_db(char *database) } } } + + if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500) + { + verbose_msg("-- Releasing savepoint...\n"); + if (mysql_query_with_error_report(mysql, 0, "RELEASE SAVEPOINT sp")) + DBUG_RETURN(1); + } + if (opt_events && mysql_get_server_version(mysql) >= 50106) { DBUG_PRINT("info", ("Dumping events for database %s", database)); @@ -4687,6 +4718,13 @@ static int dump_selected_tables(char *db, char **table_names, int tables) if (opt_xml) print_xml_tag(md_result_file, "", "\n", "database", "name=", db, NullS); + if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500) + { + verbose_msg("-- Setting savepoint...\n"); + if (mysql_query_with_error_report(mysql, 0, "SAVEPOINT sp")) + DBUG_RETURN(1); + } + /* Dump each selected table */ for (pos= dump_tables; pos < end; pos++) { @@ -4702,6 +4740,31 @@ static int dump_selected_tables(char *db, char **table_names, int tables) maybe_exit(EX_MYSQLERR); } } + + /** + ROLLBACK TO SAVEPOINT in --single-transaction mode to release metadata + lock on table which was already dumped. This allows to avoid blocking + concurrent DDL on this table without sacrificing correctness, as we + won't access table second time and dumps created by --single-transaction + mode have validity point at the start of transaction anyway. + Note that this doesn't make --single-transaction mode with concurrent + DDL safe in general case. It just improves situation for people for whom + it might be working. + */ + if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500) + { + verbose_msg("-- Rolling back to savepoint sp...\n"); + if (mysql_query_with_error_report(mysql, 0, "ROLLBACK TO SAVEPOINT sp")) + maybe_exit(EX_MYSQLERR); + } + } + + if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500) + { + verbose_msg("-- Releasing savepoint...\n"); + if (mysql_query_with_error_report(mysql, 0, "RELEASE SAVEPOINT sp")) + DBUG_RETURN(1); + } /* Dump each selected view */ diff --git a/debian/dist/Debian/control b/debian/dist/Debian/control index 2ed30bb3f9c..8114ee683ba 100644 --- a/debian/dist/Debian/control +++ b/debian/dist/Debian/control @@ -245,7 +245,8 @@ Description: MariaDB database regression test suite (metapackage depending on th Package: mariadb-connect-engine-10.0 Section: database Architecture: any -Depends: mariadb-server-10.0, unixODBC-dev, libxml2-dev +Depends: mariadb-server-10.0, unixODBC, libxml2 +Build-depends: mariadb-server-10.0, unixODBC-dev, libxml2-dev Description: Connect storage engine for MariaDB Connect engine supports a number of file formats (dbf, xml, txt, bin, etc), connections to ODBC tables and remote MySQL tables, as well as a number of diff --git a/debian/dist/Ubuntu/control b/debian/dist/Ubuntu/control index 545c780d786..16236653509 100644 --- a/debian/dist/Ubuntu/control +++ b/debian/dist/Ubuntu/control @@ -239,7 +239,8 @@ Description: MariaDB database regression test suite (metapackage depending on th Package: mariadb-connect-engine-10.0 Section: database Architecture: any -Depends: mariadb-server-10.0, unixODBC-dev, libxml2-dev +Depends: mariadb-server-10.0, unixODBC, libxml2 +Build-depends: mariadb-server-10.0, unixODBC-dev, libxml2-dev Description: Connect storage engine for MariaDB Connect engine supports a number of file formats (dbf, xml, txt, bin, etc), connections to ODBC tables and remote MySQL tables, as well as a number of diff --git a/mysql-test/include/ctype_filesort.inc b/mysql-test/include/ctype_filesort.inc index b1b7f21064d..f80637e5f88 100644 --- a/mysql-test/include/ctype_filesort.inc +++ b/mysql-test/include/ctype_filesort.inc @@ -24,3 +24,25 @@ INSERT INTO t1 VALUES (1),(2); SELECT * FROM t1 GROUP BY MID(CURRENT_USER,0) WITH ROLLUP; SELECT * FROM t1 GROUP BY MID('test',0) WITH ROLLUP; DROP TABLE t1; + +--echo # +--echo # MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +--echo # +SELECT @@collation_connection; +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +DROP TABLE t1; diff --git a/mysql-test/r/ctype_big5.result b/mysql-test/r/ctype_big5.result index aaf7cc9a371..bff5b5a250e 100644 --- a/mysql-test/r/ctype_big5.result +++ b/mysql-test/r/ctype_big5.result @@ -120,6 +120,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +big5_chinese_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; create table t1 engine=innodb select repeat('a',50) as c1; alter table t1 add index(c1(5)); insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); @@ -284,6 +335,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +big5_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; create table t1 engine=innodb select repeat('a',50) as c1; alter table t1 add index(c1(5)); insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); diff --git a/mysql-test/r/ctype_cp1250_ch.result b/mysql-test/r/ctype_cp1250_ch.result index f7cfda49db1..cb2122020b2 100644 --- a/mysql-test/r/ctype_cp1250_ch.result +++ b/mysql-test/r/ctype_cp1250_ch.result @@ -280,6 +280,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +cp1250_czech_cs +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; set global LC_MESSAGES=convert((@@global.log_bin_trust_function_creators) using cp1250); ERROR HY000: Unknown locale: '1' diff --git a/mysql-test/r/ctype_eucjpms.result b/mysql-test/r/ctype_eucjpms.result index 8b56e5ceb24..813eae74cab 100644 --- a/mysql-test/r/ctype_eucjpms.result +++ b/mysql-test/r/ctype_eucjpms.result @@ -9826,6 +9826,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +eucjpms_japanese_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; CREATE TABLE t1 AS SELECT 10 AS a, REPEAT('a',20) AS b, REPEAT('a',8) AS c, REPEAT('a',8) AS d; ALTER TABLE t1 ADD PRIMARY KEY(a), ADD KEY(b); @@ -9870,6 +9921,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +eucjpms_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; CREATE TABLE t1 AS SELECT 10 AS a, REPEAT('a',20) AS b, REPEAT('a',8) AS c, REPEAT('a',8) AS d; ALTER TABLE t1 ADD PRIMARY KEY(a), ADD KEY(b); diff --git a/mysql-test/r/ctype_euckr.result b/mysql-test/r/ctype_euckr.result index 525f14946d7..92553aa4de6 100644 --- a/mysql-test/r/ctype_euckr.result +++ b/mysql-test/r/ctype_euckr.result @@ -120,6 +120,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +euckr_korean_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; create table t1 engine=innodb select repeat('a',50) as c1; alter table t1 add index(c1(5)); insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); @@ -204,6 +255,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +euckr_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; create table t1 engine=innodb select repeat('a',50) as c1; alter table t1 add index(c1(5)); insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); diff --git a/mysql-test/r/ctype_gb2312.result b/mysql-test/r/ctype_gb2312.result index a625c0f08d3..af220466b9b 100644 --- a/mysql-test/r/ctype_gb2312.result +++ b/mysql-test/r/ctype_gb2312.result @@ -120,6 +120,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +gb2312_chinese_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; create table t1 engine=innodb select repeat('a',50) as c1; alter table t1 add index(c1(5)); insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); @@ -285,6 +336,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +gb2312_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; create table t1 engine=innodb select repeat('a',50) as c1; alter table t1 add index(c1(5)); insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); diff --git a/mysql-test/r/ctype_gbk.result b/mysql-test/r/ctype_gbk.result index 31d61a7e98a..f4d0136a34f 100644 --- a/mysql-test/r/ctype_gbk.result +++ b/mysql-test/r/ctype_gbk.result @@ -120,6 +120,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +gbk_chinese_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; create table t1 engine=innodb select repeat('a',50) as c1; alter table t1 add index(c1(5)); insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); @@ -285,6 +336,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +gbk_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; create table t1 engine=innodb select repeat('a',50) as c1; alter table t1 add index(c1(5)); insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); diff --git a/mysql-test/r/ctype_latin1.result b/mysql-test/r/ctype_latin1.result index b1507a3222b..d21570fb05f 100644 --- a/mysql-test/r/ctype_latin1.result +++ b/mysql-test/r/ctype_latin1.result @@ -335,6 +335,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +latin1_swedish_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection latin1_swedish_ci @@ -370,7 +421,7 @@ pattern varchar(64) NO INSERT INTO t1 VALUES (_utf8'2001÷01÷01',_utf8'%Y÷%m÷%d'); SELECT HEX(subject),HEX(pattern),STR_TO_DATE(subject, pattern) FROM t1; HEX(subject) HEX(pattern) STR_TO_DATE(subject, pattern) -32303031F73031F73031 2559F7256DF72564 2001-01-01 00:00:00 +32303031F73031F73031 2559F7256DF72564 2001-01-01 00:00:00.000000 DROP TABLE t1; SET collation_connection='latin1_bin'; create table t1 select repeat('a',4000) a; @@ -399,6 +450,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +latin1_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection latin1_bin diff --git a/mysql-test/r/ctype_latin1_de.result b/mysql-test/r/ctype_latin1_de.result index ceb0a65304b..d20a9c89349 100644 --- a/mysql-test/r/ctype_latin1_de.result +++ b/mysql-test/r/ctype_latin1_de.result @@ -343,6 +343,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +latin1_german2_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; "BEGIN ctype_german.inc" drop table if exists t1; create table t1 as select repeat(' ', 64) as s1; diff --git a/mysql-test/r/ctype_sjis.result b/mysql-test/r/ctype_sjis.result index 994a16261f5..ffeb8524c6e 100644 --- a/mysql-test/r/ctype_sjis.result +++ b/mysql-test/r/ctype_sjis.result @@ -98,6 +98,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +sjis_japanese_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; create table t1 engine=innodb select repeat('a',50) as c1; alter table t1 add index(c1(5)); insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); @@ -172,7 +223,7 @@ pattern varchar(64) NO INSERT INTO t1 VALUES (_utf8'2001÷01÷01',_utf8'%Y÷%m÷%d'); SELECT HEX(subject),HEX(pattern),STR_TO_DATE(subject, pattern) FROM t1; HEX(subject) HEX(pattern) STR_TO_DATE(subject, pattern) -323030318180303181803031 25598180256D81802564 2001-01-01 00:00:00 +323030318180303181803031 25598180256D81802564 2001-01-01 00:00:00.000000 DROP TABLE t1; SET collation_connection='sjis_bin'; create table t1 select repeat('a',4000) a; @@ -201,6 +252,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +sjis_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; create table t1 engine=innodb select repeat('a',50) as c1; alter table t1 add index(c1(5)); insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); diff --git a/mysql-test/r/ctype_tis620.result b/mysql-test/r/ctype_tis620.result index 70f58f91d38..08cf9f1a753 100644 --- a/mysql-test/r/ctype_tis620.result +++ b/mysql-test/r/ctype_tis620.result @@ -2964,6 +2964,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +tis620_thai_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection tis620_thai_ci @@ -3091,6 +3142,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +tis620_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection tis620_bin diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index f2b9843f4a7..c14ad3e0db3 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -5900,6 +5900,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf8_unicode_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf8_unicode_ci diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 6e5ea46fde1..e36f783196e 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -761,6 +761,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +ucs2_general_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection ucs2_general_ci @@ -929,7 +980,7 @@ pattern varchar(64) NO INSERT INTO t1 VALUES (_utf8'2001÷01÷01',_utf8'%Y÷%m÷%d'); SELECT HEX(subject),HEX(pattern),STR_TO_DATE(subject, pattern) FROM t1; HEX(subject) HEX(pattern) STR_TO_DATE(subject, pattern) -003200300030003100F70030003100F700300031 0025005900F70025006D00F700250064 2001-01-01 00:00:00 +003200300030003100F70030003100F700300031 0025005900F70025006D00F700250064 2001-01-01 00:00:00.000000 DROP TABLE t1; SET NAMES latin1; SET collation_connection='ucs2_bin'; @@ -959,6 +1010,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +ucs2_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection ucs2_bin diff --git a/mysql-test/r/ctype_ujis.result b/mysql-test/r/ctype_ujis.result index aace88419fb..77145fe2eb0 100644 --- a/mysql-test/r/ctype_ujis.result +++ b/mysql-test/r/ctype_ujis.result @@ -2234,6 +2234,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +ujis_japanese_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; create table t1 engine=innodb select repeat('a',50) as c1; alter table t1 add index(c1(5)); insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); @@ -2318,6 +2369,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +ujis_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; create table t1 engine=innodb select repeat('a',50) as c1; alter table t1 add index(c1(5)); insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); diff --git a/mysql-test/r/ctype_utf16.result b/mysql-test/r/ctype_utf16.result index 5c75bc098e3..150700bf60d 100644 --- a/mysql-test/r/ctype_utf16.result +++ b/mysql-test/r/ctype_utf16.result @@ -600,6 +600,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf16_general_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf16_general_ci @@ -647,6 +698,57 @@ i 1 DROP TABLE t1; # +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf16_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; +# # Bug#55980 Character sets: supplementary character _bin ordering is wrong # CREATE TABLE t1 AS SELECT REPEAT('a',1) AS a LIMIT 0; diff --git a/mysql-test/r/ctype_utf16_uca.result b/mysql-test/r/ctype_utf16_uca.result index 1cae0542549..a59d3dc07ff 100644 --- a/mysql-test/r/ctype_utf16_uca.result +++ b/mysql-test/r/ctype_utf16_uca.result @@ -2874,6 +2874,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf16_unicode_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf16_unicode_ci diff --git a/mysql-test/r/ctype_utf16le.result b/mysql-test/r/ctype_utf16le.result index baf3f4bb0f8..8098b0d1666 100644 --- a/mysql-test/r/ctype_utf16le.result +++ b/mysql-test/r/ctype_utf16le.result @@ -644,6 +644,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf16le_general_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf16le_general_ci @@ -690,6 +741,57 @@ i 1 DROP TABLE t1; # +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf16le_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; +# # Bug#55980 Character sets: supplementary character _bin ordering is wrong # CREATE TABLE t1 AS SELECT REPEAT('a',1) AS a LIMIT 0; diff --git a/mysql-test/r/ctype_utf32.result b/mysql-test/r/ctype_utf32.result index b67de4d0051..214ec9f9b1d 100644 --- a/mysql-test/r/ctype_utf32.result +++ b/mysql-test/r/ctype_utf32.result @@ -599,6 +599,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf32_general_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf32_general_ci @@ -646,6 +697,57 @@ i 1 DROP TABLE t1; # +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf32_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; +# # Bug#55980 Character sets: supplementary character _bin ordering is wrong # CREATE TABLE t1 AS SELECT REPEAT('a',1) AS a LIMIT 0; diff --git a/mysql-test/r/ctype_utf32_uca.result b/mysql-test/r/ctype_utf32_uca.result index a79103a687f..b77283f1ddb 100644 --- a/mysql-test/r/ctype_utf32_uca.result +++ b/mysql-test/r/ctype_utf32_uca.result @@ -2874,6 +2874,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf32_unicode_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf32_unicode_ci diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index ba96712653d..b16d98a7a19 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -963,6 +963,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf8_general_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf8_general_ci @@ -1114,7 +1165,7 @@ pattern varchar(64) NO INSERT INTO t1 VALUES (_utf8'2001÷01÷01',_utf8'%Y÷%m÷%d'); SELECT HEX(subject),HEX(pattern),STR_TO_DATE(subject, pattern) FROM t1; HEX(subject) HEX(pattern) STR_TO_DATE(subject, pattern) -32303031C3B73031C3B73031 2559C3B7256DC3B72564 2001-01-01 00:00:00 +32303031C3B73031C3B73031 2559C3B7256DC3B72564 2001-01-01 00:00:00.000000 DROP TABLE t1; SET collation_connection='utf8_bin'; create table t1 select repeat('a',4000) a; @@ -1143,6 +1194,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf8_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf8_bin diff --git a/mysql-test/r/ctype_utf8mb4.result b/mysql-test/r/ctype_utf8mb4.result index 55d5c6eed86..0dc94e90454 100644 --- a/mysql-test/r/ctype_utf8mb4.result +++ b/mysql-test/r/ctype_utf8mb4.result @@ -963,6 +963,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf8mb4_general_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf8mb4_general_ci @@ -1125,6 +1176,57 @@ i 1 DROP TABLE t1; # +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf8mb4_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; +# # Bug#55980 Character sets: supplementary character _bin ordering is wrong # CREATE TABLE t1 AS SELECT REPEAT('a',1) AS a LIMIT 0; diff --git a/mysql-test/r/ctype_utf8mb4_heap.result b/mysql-test/r/ctype_utf8mb4_heap.result index 18c8ec69f83..57d29a24fd0 100644 --- a/mysql-test/r/ctype_utf8mb4_heap.result +++ b/mysql-test/r/ctype_utf8mb4_heap.result @@ -902,6 +902,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf8mb4_general_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf8mb4_general_ci @@ -1063,6 +1114,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf8mb4_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf8mb4_bin diff --git a/mysql-test/r/ctype_utf8mb4_innodb.result b/mysql-test/r/ctype_utf8mb4_innodb.result index 68986e28dea..ba03a3f66e6 100644 --- a/mysql-test/r/ctype_utf8mb4_innodb.result +++ b/mysql-test/r/ctype_utf8mb4_innodb.result @@ -963,6 +963,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf8mb4_general_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf8mb4_general_ci @@ -1124,6 +1175,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf8mb4_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf8mb4_bin diff --git a/mysql-test/r/ctype_utf8mb4_myisam.result b/mysql-test/r/ctype_utf8mb4_myisam.result index 8a2de245093..c4ff8e0a882 100644 --- a/mysql-test/r/ctype_utf8mb4_myisam.result +++ b/mysql-test/r/ctype_utf8mb4_myisam.result @@ -963,6 +963,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf8mb4_general_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf8mb4_general_ci @@ -1124,6 +1175,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +utf8mb4_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; select @@collation_connection; @@collation_connection utf8mb4_bin diff --git a/mysql-test/r/date_formats.result b/mysql-test/r/date_formats.result index ff3f4038447..8439c40fbf9 100644 --- a/mysql-test/r/date_formats.result +++ b/mysql-test/r/date_formats.result @@ -60,70 +60,70 @@ insert into t1 values ('15-2001-1', '%d-%Y-%c'); select date,format,str_to_date(date, format) as str_to_date from t1; date format str_to_date -2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12 -03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02 -0003-01-02 8:11:2.123456 %Y-%m-%d %H:%i:%S.%# 0003-01-02 08:11:02 -03-01-02 8:11:2.123456 %Y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02 -2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12 +2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12.000000 +03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02.000000 +0003-01-02 8:11:2.123456 %Y-%m-%d %H:%i:%S.%# 0003-01-02 08:11:02.000000 +03-01-02 8:11:2.123456 %Y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02.000000 +2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12.000000 2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.123450 2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.123450 2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.123450 -2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12 -10:20:10 %H:%i:%s 0000-00-00 10:20:10 -10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10 -10:20:10 %T 0000-00-00 10:20:10 -10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10 -10:20:10AM %r 0000-00-00 10:20:10 +2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12.000000 +10:20:10 %H:%i:%s 0000-00-00 10:20:10.000000 +10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10.000000 +10:20:10 %T 0000-00-00 10:20:10.000000 +10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10.000000 +10:20:10AM %r 0000-00-00 10:20:10.000000 10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.440000 -15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58 -15 September 2001 %d %M %Y 2001-09-15 00:00:00 -15 SEPTEMB 2001 %d %M %Y 2001-09-15 00:00:00 -15 MAY 2001 %d %b %Y 2001-05-15 00:00:00 -15th May 2001 %D %b %Y 2001-05-15 00:00:00 -Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 -Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 -Tuesday 00 2002 %W %U %Y 2002-01-01 00:00:00 -Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00 -Sunday 01 2001 %W %v %x 2001-01-07 00:00:00 -Tuesday 52 2001 %W %V %X 2002-01-01 00:00:00 -060 2004 %j %Y 2004-02-29 00:00:00 -4 53 1998 %w %u %Y 1998-12-31 00:00:00 -15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 00:00:00 -15-01-20 %d-%m-%y 2020-01-15 00:00:00 -15-2001-1 %d-%Y-%c 2001-01-15 00:00:00 +15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58.000000 +15 September 2001 %d %M %Y 2001-09-15 00:00:00.000000 +15 SEPTEMB 2001 %d %M %Y 2001-09-15 00:00:00.000000 +15 MAY 2001 %d %b %Y 2001-05-15 00:00:00.000000 +15th May 2001 %D %b %Y 2001-05-15 00:00:00.000000 +Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00.000000 +Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00.000000 +Tuesday 00 2002 %W %U %Y 2002-01-01 00:00:00.000000 +Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00.000000 +Sunday 01 2001 %W %v %x 2001-01-07 00:00:00.000000 +Tuesday 52 2001 %W %V %X 2002-01-01 00:00:00.000000 +060 2004 %j %Y 2004-02-29 00:00:00.000000 +4 53 1998 %w %u %Y 1998-12-31 00:00:00.000000 +15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 00:00:00.000000 +15-01-20 %d-%m-%y 2020-01-15 00:00:00.000000 +15-2001-1 %d-%Y-%c 2001-01-15 00:00:00.000000 select date,format,concat('',str_to_date(date, format)) as con from t1; date format con -2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12 -03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02 -0003-01-02 8:11:2.123456 %Y-%m-%d %H:%i:%S.%# 0003-01-02 08:11:02 -03-01-02 8:11:2.123456 %Y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02 -2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12 +2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12.000000 +03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02.000000 +0003-01-02 8:11:2.123456 %Y-%m-%d %H:%i:%S.%# 0003-01-02 08:11:02.000000 +03-01-02 8:11:2.123456 %Y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02.000000 +2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12.000000 2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.123450 2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.123450 2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.123450 -2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12 -10:20:10 %H:%i:%s 0000-00-00 10:20:10 -10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10 -10:20:10 %T 0000-00-00 10:20:10 -10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10 -10:20:10AM %r 0000-00-00 10:20:10 +2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12.000000 +10:20:10 %H:%i:%s 0000-00-00 10:20:10.000000 +10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10.000000 +10:20:10 %T 0000-00-00 10:20:10.000000 +10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10.000000 +10:20:10AM %r 0000-00-00 10:20:10.000000 10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.440000 -15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58 -15 September 2001 %d %M %Y 2001-09-15 00:00:00 -15 SEPTEMB 2001 %d %M %Y 2001-09-15 00:00:00 -15 MAY 2001 %d %b %Y 2001-05-15 00:00:00 -15th May 2001 %D %b %Y 2001-05-15 00:00:00 -Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 -Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 -Tuesday 00 2002 %W %U %Y 2002-01-01 00:00:00 -Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00 -Sunday 01 2001 %W %v %x 2001-01-07 00:00:00 -Tuesday 52 2001 %W %V %X 2002-01-01 00:00:00 -060 2004 %j %Y 2004-02-29 00:00:00 -4 53 1998 %w %u %Y 1998-12-31 00:00:00 -15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 00:00:00 -15-01-20 %d-%m-%y 2020-01-15 00:00:00 -15-2001-1 %d-%Y-%c 2001-01-15 00:00:00 +15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58.000000 +15 September 2001 %d %M %Y 2001-09-15 00:00:00.000000 +15 SEPTEMB 2001 %d %M %Y 2001-09-15 00:00:00.000000 +15 MAY 2001 %d %b %Y 2001-05-15 00:00:00.000000 +15th May 2001 %D %b %Y 2001-05-15 00:00:00.000000 +Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00.000000 +Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00.000000 +Tuesday 00 2002 %W %U %Y 2002-01-01 00:00:00.000000 +Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00.000000 +Sunday 01 2001 %W %v %x 2001-01-07 00:00:00.000000 +Tuesday 52 2001 %W %V %X 2002-01-01 00:00:00.000000 +060 2004 %j %Y 2004-02-29 00:00:00.000000 +4 53 1998 %w %u %Y 1998-12-31 00:00:00.000000 +15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 00:00:00.000000 +15-01-20 %d-%m-%y 2020-01-15 00:00:00.000000 +15-2001-1 %d-%Y-%c 2001-01-15 00:00:00.000000 select date,format,cast(str_to_date(date, format) as datetime) as datetime from t1; date format datetime 2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12 @@ -352,16 +352,16 @@ insert into t1 values ('03-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p'); select date,format,str_to_date(date, format) as str_to_date from t1; date format str_to_date -10:20:10AM %h:%i:%s 0000-00-00 10:20:10 -2003-01-02 10:11:12 %Y-%m-%d %h:%i:%S 2003-01-02 10:11:12 -03-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12 +10:20:10AM %h:%i:%s 0000-00-00 10:20:10.000000 +2003-01-02 10:11:12 %Y-%m-%d %h:%i:%S 2003-01-02 10:11:12.000000 +03-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12.000000 Warnings: Warning 1292 Truncated incorrect datetime value: '10:20:10AM' select date,format,concat(str_to_date(date, format),'') as con from t1; date format con -10:20:10AM %h:%i:%s 0000-00-00 10:20:10 -2003-01-02 10:11:12 %Y-%m-%d %h:%i:%S 2003-01-02 10:11:12 -03-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12 +10:20:10AM %h:%i:%s 0000-00-00 10:20:10.000000 +2003-01-02 10:11:12 %Y-%m-%d %h:%i:%S 2003-01-02 10:11:12.000000 +03-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12.000000 Warnings: Warning 1292 Truncated incorrect datetime value: '10:20:10AM' drop table t1; @@ -418,7 +418,7 @@ drop table t1; create table t1 select "02 10" as a, "%d %H" as b; select str_to_date(a,b) from t1; str_to_date(a,b) -0000-00-02 10:00:00 +0000-00-02 10:00:00.000000 create table t2 select str_to_date(a,b) from t1; describe t2; Field Type Null Key Default Extra diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 400e3fdc544..cebba082ea4 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -1945,6 +1945,74 @@ SELECT 1 FROM DUAL WHERE MINUTE(TIMEDIFF(NULL, '12:12:12')); SELECT 1 FROM DUAL WHERE SECOND(TIMEDIFF(NULL, '12:12:12')); 1 # +# MDEV-4511 Assertion `scale <= precision' fails on GROUP BY TIMEDIFF with incorrect types +# +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT a FROM t1 GROUP BY TIMEDIFF('2004-06-12',a) * 1; +a +2005-05-04 +Warnings: +Warning 1292 Truncated incorrect time value: '2004-06-12' +Warning 1292 Truncated incorrect time value: '2004-06-12' +DROP TABLE t1; +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT a FROM t1 GROUP BY ADDTIME(a,'10')*1; +a +2000-02-23 +2005-05-04 +DROP TABLE t1; +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY SEC_TO_TIME(concat(a,'10'))*1; +a +2000-02-23 +2005-05-04 +DROP TABLE t1; +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY ADDTIME(timestamp('2001-01-01 00:00:00'),CAST(a AS SIGNED)&0xF)*1; +a +2005-05-04 +2000-02-23 +DROP TABLE t1; +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY STR_TO_DATE(a,concat('%Y-%m-%d.%f',if(rand(),'','')))*1; +a +2000-02-23 +2005-05-04 +DROP TABLE t1; +CREATE TABLE t1 AS SELECT +STR_TO_DATE('2001-01-01', '%Y-%m-%d') AS date_only, +STR_TO_DATE('10:10:10', '%H:%i:%s') AS time_only, +STR_TO_DATE('10:10:10.123', '%H:%i:%s.%f') AS time_microsecond, +STR_TO_DATE('2001-01-01 10:10:10', '%Y-%m-%d %H:%i:%s') AS date_time, +STR_TO_DATE('2001-01-01 10:10:10.123', '%Y-%m-%d %H:%i:%s.%f') AS date_time_microsecond; +SHOW COLUMNS FROM t1; +Field Type Null Key Default Extra +date_only date YES NULL +time_only time YES NULL +time_microsecond time(6) YES NULL +date_time datetime YES NULL +date_time_microsecond datetime(6) YES NULL +DROP TABLE t1; +CREATE TABLE t1 AS SELECT +SEC_TO_TIME(1)+0.1, +SEC_TO_TIME(1.1)+0.1, +SEC_TO_TIME(1.12)+0.1, +SEC_TO_TIME(1.123456)+0.1, +SEC_TO_TIME(1.1234567)+0.1; +SHOW COLUMNS FROM t1; +Field Type Null Key Default Extra +SEC_TO_TIME(1)+0.1 decimal(12,1) YES NULL +SEC_TO_TIME(1.1)+0.1 decimal(13,1) YES NULL +SEC_TO_TIME(1.12)+0.1 decimal(14,2) YES NULL +SEC_TO_TIME(1.123456)+0.1 decimal(18,6) YES NULL +SEC_TO_TIME(1.1234567)+0.1 decimal(18,6) YES NULL +DROP TABLE t1; +# # MDEV-4635 Crash in UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y')) # SET TIME_ZONE='+02:00'; diff --git a/mysql-test/r/locale.result b/mysql-test/r/locale.result index aa61d8cd86f..1335f1ec9d5 100644 --- a/mysql-test/r/locale.result +++ b/mysql-test/r/locale.result @@ -90,3 +90,99 @@ SELECT DATE_FORMAT('2001-01-07', '%w %a %W'); DATE_FORMAT('2001-01-07', '%w %a %W') 0 Du Duminică End of 5.4 tests +# +# Start of 5.6 tests +# +# +# WL#5303 Romansh locale for DAYNAME, MONTHNAME, DATE_FORMAT +# +SET NAMES utf8; +SET @old_50915_lc_time_names := @@lc_time_names; +SET lc_time_names=en_US; +SELECT DATE_FORMAT('2001-01-01', '%w %a %W'); +DATE_FORMAT('2001-01-01', '%w %a %W') +1 Mon Monday +SELECT DATE_FORMAT('2001-03-01', '%c %b %M'); +DATE_FORMAT('2001-03-01', '%c %b %M') +3 Mar March +SET lc_time_names=rm_CH; +SELECT DATE_FORMAT('2001-01-01', '%w %a %W'); +DATE_FORMAT('2001-01-01', '%w %a %W') +1 gli glindesdi +SELECT DATE_FORMAT('2001-01-02', '%w %a %W'); +DATE_FORMAT('2001-01-02', '%w %a %W') +2 ma mardi +SELECT DATE_FORMAT('2001-01-03', '%w %a %W'); +DATE_FORMAT('2001-01-03', '%w %a %W') +3 me mesemna +SELECT DATE_FORMAT('2001-01-04', '%w %a %W'); +DATE_FORMAT('2001-01-04', '%w %a %W') +4 gie gievgia +SELECT DATE_FORMAT('2001-01-05', '%w %a %W'); +DATE_FORMAT('2001-01-05', '%w %a %W') +5 ve venderdi +SELECT DATE_FORMAT('2001-01-06', '%w %a %W'); +DATE_FORMAT('2001-01-06', '%w %a %W') +6 so sonda +SELECT DATE_FORMAT('2001-01-07', '%w %a %W'); +DATE_FORMAT('2001-01-07', '%w %a %W') +0 du dumengia +SELECT DATE_FORMAT('2001-01-01', '%c %b %M'); +DATE_FORMAT('2001-01-01', '%c %b %M') +1 schan schaner +SELECT DATE_FORMAT('2001-02-01', '%c %b %M'); +DATE_FORMAT('2001-02-01', '%c %b %M') +2 favr favrer +SELECT DATE_FORMAT('2001-03-01', '%c %b %M'); +DATE_FORMAT('2001-03-01', '%c %b %M') +3 mars mars +SELECT DATE_FORMAT('2001-04-01', '%c %b %M'); +DATE_FORMAT('2001-04-01', '%c %b %M') +4 avr avrigl +SELECT DATE_FORMAT('2001-05-01', '%c %b %M'); +DATE_FORMAT('2001-05-01', '%c %b %M') +5 matg matg +SELECT DATE_FORMAT('2001-06-01', '%c %b %M'); +DATE_FORMAT('2001-06-01', '%c %b %M') +6 zercl zercladur +SELECT DATE_FORMAT('2001-07-01', '%c %b %M'); +DATE_FORMAT('2001-07-01', '%c %b %M') +7 fan fanadur +SELECT DATE_FORMAT('2001-08-01', '%c %b %M'); +DATE_FORMAT('2001-08-01', '%c %b %M') +8 avust avust +SELECT DATE_FORMAT('2001-09-01', '%c %b %M'); +DATE_FORMAT('2001-09-01', '%c %b %M') +9 sett settember +SELECT DATE_FORMAT('2001-10-01', '%c %b %M'); +DATE_FORMAT('2001-10-01', '%c %b %M') +10 oct october +SELECT DATE_FORMAT('2001-11-01', '%c %b %M'); +DATE_FORMAT('2001-11-01', '%c %b %M') +11 nov november +SELECT DATE_FORMAT('2001-12-01', '%c %b %M'); +DATE_FORMAT('2001-12-01', '%c %b %M') +12 dec december +SET lc_time_names=de_CH; +SELECT DATE_FORMAT('2001-01-06', '%w %a %W'); +DATE_FORMAT('2001-01-06', '%w %a %W') +6 Sa Samstag +SELECT DATE_FORMAT('2001-09-01', '%c %b %M'); +DATE_FORMAT('2001-09-01', '%c %b %M') +9 Sep September +SELECT DATE_FORMAT('2010-03-23 11:00:00','%h %p'); +DATE_FORMAT('2010-03-23 11:00:00','%h %p') +11 AM +SELECT DATE_FORMAT('2010-03-23 13:00:00','%h %p'); +DATE_FORMAT('2010-03-23 13:00:00','%h %p') +01 PM +SELECT format(123456789,2,'rm_CH'); +format(123456789,2,'rm_CH') +123'456'789,00 +SET lc_messages=rm_CH; +SELECT * FROM non_existent; +ERROR 42S02: Table 'test.non_existent' doesn't exist +SET lc_time_names=@old_50915_lc_time_names; +# +# End of 5.6 tests +# diff --git a/mysql-test/r/mysql_upgrade.result b/mysql-test/r/mysql_upgrade.result index cf4f54658b4..08eafcc1d5e 100644 --- a/mysql-test/r/mysql_upgrade.result +++ b/mysql-test/r/mysql_upgrade.result @@ -329,4 +329,65 @@ performance_schema test Phase 3/3: Running 'mysql_fix_privilege_tables'... OK +# +# MDEV-4332 Increase username length from 16 characters +# MDEV-6068, MDEV-6178 mysql_upgrade breaks databases with long user names +# +GRANT SELECT ON mysql.* TO very_long_user_name_number_1; +GRANT SELECT ON mysql.* TO very_long_user_name_number_2; +GRANT ALL ON *.* TO even_longer_user_name_number_3_to_test_the_grantor_and_definer_field_length@localhost WITH GRANT OPTION; +GRANT INSERT ON mysql.user TO very_long_user_name_number_1; +GRANT INSERT ON mysql.user TO very_long_user_name_number_2; +GRANT UPDATE (User) ON mysql.db TO very_long_user_name_number_1; +GRANT UPDATE (User) ON mysql.db TO very_long_user_name_number_2; +CREATE PROCEDURE test.pr() BEGIN END; +Phase 1/3: Fixing table and database names +Phase 2/3: Checking and upgrading tables +Processing databases +information_schema +mtr +mtr.global_suppressions OK +mtr.test_suppressions OK +mysql +mysql.column_stats OK +mysql.columns_priv OK +mysql.db OK +mysql.event OK +mysql.func OK +mysql.gtid_slave_pos OK +mysql.help_category OK +mysql.help_keyword OK +mysql.help_relation OK +mysql.help_topic OK +mysql.host OK +mysql.index_stats OK +mysql.innodb_index_stats OK +mysql.innodb_table_stats OK +mysql.plugin OK +mysql.proc OK +mysql.procs_priv OK +mysql.proxies_priv OK +mysql.roles_mapping OK +mysql.servers OK +mysql.table_stats OK +mysql.tables_priv OK +mysql.time_zone OK +mysql.time_zone_leap_second OK +mysql.time_zone_name OK +mysql.time_zone_transition OK +mysql.time_zone_transition_type OK +mysql.user OK +performance_schema +test +Phase 3/3: Running 'mysql_fix_privilege_tables'... +OK +SELECT definer FROM mysql.proc WHERE db = 'test' AND name = 'pr'; +definer +even_longer_user_name_number_3_to_test_the_grantor_and_definer_field_length@localhost +SELECT grantor FROM mysql.tables_priv WHERE db = 'mysql' AND table_name = 'user'; +grantor +even_longer_user_name_number_3_to_test_the_grantor_and_definer_field_length@localhost +even_longer_user_name_number_3_to_test_the_grantor_and_definer_field_length@localhost +DROP USER very_long_user_name_number_1, very_long_user_name_number_2, even_longer_user_name_number_3_to_test_the_grantor_and_definer_field_length@localhost; +DROP PROCEDURE test.pr; End of tests diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index c67a7a00425..9dedbd1d133 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -5206,12 +5206,16 @@ INSERT INTO b12809202_db.t2 VALUES (1), (2), (3); -- Connecting to localhost... -- main : logs flushed successfully! -- Starting transaction... +-- Setting savepoint... -- Retrieving table structure for table t1... -- Sending SELECT query... -- Retrieving rows... +-- Rolling back to savepoint sp... -- Retrieving table structure for table t2... -- Sending SELECT query... -- Retrieving rows... +-- Rolling back to savepoint sp... +-- Releasing savepoint... -- Disconnecting from localhost... #### Dump ends here #### diff --git a/mysql-test/r/selectivity_no_engine.result b/mysql-test/r/selectivity_no_engine.result index 6516abbe318..da39ec1b3b4 100644 --- a/mysql-test/r/selectivity_no_engine.result +++ b/mysql-test/r/selectivity_no_engine.result @@ -139,6 +139,82 @@ Warnings: Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`col1` AS `col1`,`test`.`t2`.`col2` AS `col2` from `test`.`t2` where ((`test`.`t2`.`a` in (1,2,3)) and (`test`.`t2`.`b` in (1,2,3))) drop table t2, t1; # +# MDEV-5980: EITS: if condition is used for REF access, its selectivity is still in filtered% +# +create table t0(a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1(key1 int, col1 int, key(key1)); +insert into t1 select A.a, A.a from t0 A, t0 B, t0 C; +set histogram_size=100; +set use_stat_tables='preferably'; +set optimizer_use_condition_selectivity=4; +analyze table t1 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status Table is already up to date +# 10% is ok +explain extended select * from t1 where col1=2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 1000 9.90 Using where +Warnings: +Note 1003 select `test`.`t1`.`key1` AS `key1`,`test`.`t1`.`col1` AS `col1` from `test`.`t1` where (`test`.`t1`.`col1` = 2) +# Must show 100%, not 10% +explain extended select * from t1 where key1=2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ref key1 key1 5 const 98 100.00 +Warnings: +Note 1003 select `test`.`t1`.`key1` AS `key1`,`test`.`t1`.`col1` AS `col1` from `test`.`t1` where (`test`.`t1`.`key1` = 2) +drop table t0, t1; +# MDEV-6003: EITS: ref access, keypart2=const vs keypart2=expr - inconsistent filtered% value +# +create table t0(a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 ( +kp1 int, kp2 int, +filler1 char(100), +filler2 char(100), +key(kp1, kp2) +); +insert into t1 +select +A.a, +B.a, +'filler-data-1', +'filler-data-2' +from t0 A, t0 B, t0 C; +set histogram_size=100; +set use_stat_tables='preferably'; +set optimizer_use_condition_selectivity=4; +analyze table t1 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status Table is already up to date +# NOTE: 10*100%, 10*100% rows is ok +explain extended select * from t0, t1 where t1.kp1=t0.a and t1.kp2=t0.a+1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 100.00 Using where +1 SIMPLE t1 ref kp1 kp1 10 test.t0.a,func 10 100.00 Using index condition +Warnings: +Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t1`.`kp1` AS `kp1`,`test`.`t1`.`kp2` AS `kp2`,`test`.`t1`.`filler1` AS `filler1`,`test`.`t1`.`filler2` AS `filler2` from `test`.`t0` join `test`.`t1` where ((`test`.`t1`.`kp1` = `test`.`t0`.`a`) and (`test`.`t1`.`kp2` = (`test`.`t0`.`a` + 1))) +# NOTE: t0: 10*100% is ok, t1: 10*9.90% is bad. t1 should have 10*100%. +explain extended select * from t0, t1 where t1.kp1=t0.a and t1.kp2=4; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 100.00 Using where +1 SIMPLE t1 ref kp1 kp1 10 test.t0.a,const 10 100.00 +Warnings: +Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t1`.`kp1` AS `kp1`,`test`.`t1`.`kp2` AS `kp2`,`test`.`t1`.`filler1` AS `filler1`,`test`.`t1`.`filler2` AS `filler2` from `test`.`t0` join `test`.`t1` where ((`test`.`t1`.`kp1` = `test`.`t0`.`a`) and (`test`.`t1`.`kp2` = 4)) +drop table t0, t1; +# +# MDEV-6209: Assertion `join->best_read < double(1.79769313486231570815e+308L)' +# failed in bool greedy_search with optimizer_use_condition_selectivity>1 +# +SET optimizer_use_condition_selectivity = 2; +CREATE TABLE t1 (a CHAR(6), b INT, PRIMARY KEY (a,b)) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('foo',1),('bar',2); +SELECT * FROM t1 AS t1_1, t1 AS t1_2 WHERE NOT ( t1_1.a <> 'baz'); +a b a b +DROP TABLE t1; +# # End of the test file # set use_stat_tables= @save_use_stat_tables; diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result index 03b942be3f6..e23c8640dfc 100644 --- a/mysql-test/r/type_date.result +++ b/mysql-test/r/type_date.result @@ -161,7 +161,7 @@ INSERT INTO t1 VALUES (1); INSERT INTO t1 VALUES (NULL); SELECT str_to_date( '', a ) FROM t1; str_to_date( '', a ) -0000-00-00 00:00:00 +0000-00-00 00:00:00.000000 NULL DROP TABLE t1; CREATE TABLE t1 (a DATE, b INT, PRIMARY KEY (a,b)); diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index eb896082810..2ba64ed3003 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -801,16 +801,16 @@ select @@lc_time_names; @@lc_time_names en_US LC_TIME_NAMES: testing locale with the last ID: -set lc_time_names=109; -select @@lc_time_names; -@@lc_time_names -el_GR -LC_TIME_NAMES: testing a number beyond the valid ID range: set lc_time_names=110; -ERROR HY000: Unknown locale: '110' select @@lc_time_names; @@lc_time_names -el_GR +rm_CH +LC_TIME_NAMES: testing a number beyond the valid ID range: +set lc_time_names=111; +ERROR HY000: Unknown locale: '111' +select @@lc_time_names; +@@lc_time_names +rm_CH LC_TIME_NAMES: testing that 0 is en_US: set lc_time_names=0; select @@lc_time_names; diff --git a/mysql-test/suite/binlog/r/binlog_row_ctype_cp932.result b/mysql-test/suite/binlog/r/binlog_row_ctype_cp932.result index 8bdad1813ea..a6d997f653a 100644 --- a/mysql-test/suite/binlog/r/binlog_row_ctype_cp932.result +++ b/mysql-test/suite/binlog/r/binlog_row_ctype_cp932.result @@ -11435,6 +11435,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +cp932_japanese_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; CREATE TABLE t1 AS SELECT 10 AS a, REPEAT('a',20) AS b, REPEAT('a',8) AS c, REPEAT('a',8) AS d; ALTER TABLE t1 ADD PRIMARY KEY(a), ADD KEY(b); @@ -11479,6 +11530,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +cp932_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; CREATE TABLE t1 AS SELECT 10 AS a, REPEAT('a',20) AS b, REPEAT('a',8) AS c, REPEAT('a',8) AS d; ALTER TABLE t1 ADD PRIMARY KEY(a), ADD KEY(b); diff --git a/mysql-test/suite/binlog/r/binlog_stm_ctype_cp932.result b/mysql-test/suite/binlog/r/binlog_stm_ctype_cp932.result index 8bdad1813ea..a6d997f653a 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_ctype_cp932.result +++ b/mysql-test/suite/binlog/r/binlog_stm_ctype_cp932.result @@ -11435,6 +11435,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +cp932_japanese_ci +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; CREATE TABLE t1 AS SELECT 10 AS a, REPEAT('a',20) AS b, REPEAT('a',8) AS c, REPEAT('a',8) AS d; ALTER TABLE t1 ADD PRIMARY KEY(a), ADD KEY(b); @@ -11479,6 +11530,57 @@ i 1 1 DROP TABLE t1; +# +# MDEV-6170 Incorrect ordering with utf8_bin and utf8mb4_bin collations +# +SELECT @@collation_connection; +@@collation_connection +cp932_bin +CREATE TABLE t1 ENGINE=MEMORY AS SELECT REPEAT('a',5) AS a LIMIT 0; +INSERT INTO t1 (a) VALUES ("a"); +INSERT INTO t1 (a) VALUES ("b"); +INSERT INTO t1 (a) VALUES ("c"); +INSERT INTO t1 (a) VALUES ("d"); +INSERT INTO t1 (a) VALUES ("e"); +INSERT INTO t1 (a) VALUES ("f"); +INSERT INTO t1 (a) VALUES ("g"); +INSERT INTO t1 (a) VALUES ("h"); +INSERT INTO t1 (a) VALUES ("i"); +INSERT INTO t1 (a) VALUES ("j"); +INSERT INTO t1 (a) VALUES ("k"); +INSERT INTO t1 (a) VALUES ("l"); +INSERT INTO t1 (a) VALUES ("m"); +SELECT * FROM t1 ORDER BY LOWER(a); +a +a +b +c +d +e +f +g +h +i +j +k +l +m +SELECT * FROM t1 ORDER BY LOWER(a) DESC; +a +m +l +k +j +i +h +g +f +e +d +c +b +a +DROP TABLE t1; CREATE TABLE t1 AS SELECT 10 AS a, REPEAT('a',20) AS b, REPEAT('a',8) AS c, REPEAT('a',8) AS d; ALTER TABLE t1 ADD PRIMARY KEY(a), ADD KEY(b); diff --git a/mysql-test/suite/innodb/r/help_url.result b/mysql-test/suite/innodb/r/help_url.result index 9a4efa3a185..10affe78f0c 100644 --- a/mysql-test/suite/innodb/r/help_url.result +++ b/mysql-test/suite/innodb/r/help_url.result @@ -1,4 +1,4 @@ create table innodb_table_monitor (a int) engine=InnoDB; Warnings: -Warning 131 Using innodb_table_monitor is deprecated and it may be removed in future releases. Please use the InnoDB INFORMATION_SCHEMA tables instead, see http://dev.mysql.com/doc/refman/5.6/en/innodb-i_s-tables.html +Warning 131 Using the table name innodb_table_monitor to enable diagnostic output is deprecated and may be removed in future releases. Use INFORMATION_SCHEMA or PERFORMANCE_SCHEMA tables or SET GLOBAL innodb_status_output=ON. drop table innodb_table_monitor; 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 0f50d6943a8..9f5c1f271fc 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 @@ -44,6 +44,7 @@ id2 3 SELECT id1 FROM t1 WHERE MATCH (a1,b1) AGAINST ('tutorial (+mysql -VÐƷWİ)' IN BOOLEAN MODE) ; id1 +1 3 6 2 @@ -51,6 +52,7 @@ id1 5 SELECT id2 FROM t2 WHERE MATCH (a2,b2) AGAINST ('tutorial (+mysql -VÐƷWİ)' IN BOOLEAN MODE) ; id2 +1 3 6 2 @@ -89,12 +91,14 @@ SELECT id1 FROM t1 WHERE MATCH (a1,b1) AGAINST ('tutorial (+mysql -VÐƷWİ)' IN id1 SELECT id2 FROM t2 WHERE MATCH (a2,b2) AGAINST ('tutorial (+mysql -VÐƷWİ)' IN BOOLEAN MODE) ; id2 +3 6 SELECT id1 FROM t1 WHERE MATCH (a1,b1) AGAINST ('+update +cascade' IN BOOLEAN MODE) ; id1 4 2 6 +1 5 3 SELECT id2 FROM t2 WHERE MATCH (a2,b2) AGAINST ('+update +cascade' IN BOOLEAN MODE) ; @@ -102,10 +106,12 @@ id2 4 2 6 +1 5 3 SELECT id2 FROM t2 WHERE a2 LIKE '%UPDATE CASCADE%'; id2 +1 2 3 4 @@ -212,10 +218,8 @@ SELECT * FROM t2 WHERE MATCH (a2,b2) AGAINST ('tutorial (+mysql -VÐƷWİ)' IN B id2 a2 b2 SELECT * FROM t1 WHERE a1 LIKE '%tutorial%'; id1 a1 b1 -1 MySQL Tutorial DBMS stands for DataBase VÐƷWİ... SELECT * FROM t2 WHERE a2 LIKE '%tutorial%'; id2 a2 b2 -1 MySQL Tutorial DBMS stands for DataBase VÐƷWİ... DROP TABLE t2 , t1; DROP TABLE IF EXISTS t2,t1; SET NAMES utf8; @@ -265,10 +269,12 @@ id2 a2 b2 SELECT * FROM t1 WHERE MATCH (a1,b1) AGAINST ('tutorial (+mysql -VÐƷWİ)' IN BOOLEAN MODE) ; id1 a1 b1 3 Optimizing MySQL In this tutorial we will show ... +1 MySQL Tutorial DBMS stands for DataBase VÐƷWİ... 2 How To Use MySQL Well After you went through a ... SELECT * FROM t2 WHERE MATCH (a2,b2) AGAINST ('tutorial (+mysql -VÐƷWİ)' IN BOOLEAN MODE) ; id2 a2 b2 3 Optimizing MySQL In this tutorial we will show ... +1 MySQL Tutorial DBMS stands for DataBase VÐƷWİ... 2 How To Use MySQL Well After you went through a ... SELECT * FROM t1 WHERE MATCH (a1,b1) AGAINST ('tutorial' WITH QUERY EXPANSION) ; id1 a1 b1 @@ -327,12 +333,14 @@ SELECT * FROM t1 WHERE MATCH (a1,b1) AGAINST ('tutorial (+mysql -VÐƷWİ)' IN B id1 a1 b1 SELECT * FROM t2 WHERE MATCH (a2,b2) AGAINST ('tutorial (+mysql -VÐƷWİ)' IN BOOLEAN MODE) ; id2 a2 b2 +3 changing column - on UPDATE cascade In this tutorial we will show ... 6 changing column - on UPDATE cascade When configured properly, MySQL ... SELECT * FROM t1 WHERE MATCH (a1,b1) AGAINST ('+UPDATE +cascade' IN BOOLEAN MODE) ; id1 a1 b1 4 changing column - on UPDATE cascade to check foreign constraint 2 changing column - on UPDATE cascade to check foreign constraint 6 changing column - on UPDATE cascade to check foreign constraint +1 changing column - on UPDATE cascade to check foreign constraint 5 changing column - on UPDATE cascade to check foreign constraint 3 changing column - on UPDATE cascade to check foreign constraint SELECT * FROM t2 WHERE MATCH (a2,b2) AGAINST ('+UPDATE +cascade' IN BOOLEAN MODE) ; @@ -340,10 +348,12 @@ id2 a2 b2 4 changing column - on UPDATE cascade 1. Never run mysqld as root. 2. ... 2 changing column - on UPDATE cascade After you went through a ... 6 changing column - on UPDATE cascade When configured properly, MySQL ... +1 changing column - on UPDATE cascade DBMS stands for DataBase VÐƷWİ... 5 changing column - on UPDATE cascade In the following database comparison ... 3 changing column - on UPDATE cascade In this tutorial we will show ... SELECT * FROM t2 WHERE a2 LIKE '%UPDATE CASCADE%'; id2 a2 b2 +1 changing column - on UPDATE cascade DBMS stands for DataBase VÐƷWİ... 2 changing column - on UPDATE cascade After you went through a ... 3 changing column - on UPDATE cascade In this tutorial we will show ... 4 changing column - on UPDATE cascade 1. Never run mysqld as root. 2. ... diff --git a/mysql-test/suite/perfschema/r/threads_innodb,xtradb.rdiff b/mysql-test/suite/perfschema/r/threads_innodb,xtradb.rdiff new file mode 100644 index 00000000000..bfa17407049 --- /dev/null +++ b/mysql-test/suite/perfschema/r/threads_innodb,xtradb.rdiff @@ -0,0 +1,10 @@ +--- suite/perfschema/r/threads_innodb.result 2013-12-20 20:19:06.000000000 +0100 ++++ suite/perfschema/r/threads_innodb.reject 2014-05-06 13:08:05.000000000 +0200 +@@ -6,6 +6,7 @@ + GROUP BY name; + name type processlist_user processlist_host processlist_db processlist_command processlist_time processlist_state processlist_info parent_thread_id role instrumented + thread/innodb/io_handler_thread BACKGROUND NULL NULL NULL NULL NULL NULL NULL NULL NULL YES ++thread/innodb/lru_manager_thread BACKGROUND NULL NULL NULL NULL NULL NULL NULL NULL NULL YES + thread/innodb/page_cleaner_thread BACKGROUND NULL NULL NULL NULL NULL NULL NULL NULL NULL YES + thread/innodb/srv_error_monitor_thread BACKGROUND NULL NULL NULL NULL NULL NULL NULL NULL NULL YES + thread/innodb/srv_lock_timeout_thread BACKGROUND NULL NULL NULL NULL NULL NULL NULL NULL NULL YES diff --git a/mysql-test/suite/plugins/r/locales.result b/mysql-test/suite/plugins/r/locales.result index 45f80353697..9c65f8d6034 100644 --- a/mysql-test/suite/plugins/r/locales.result +++ b/mysql-test/suite/plugins/r/locales.result @@ -110,3 +110,4 @@ ID NAME DESCRIPTION MAX_MONTH_NAME_LENGTH MAX_DAY_NAME_LENGTH DECIMAL_POINT THOU 107 sv_FI Swedish - Finland 9 7 , swedish 108 zh_HK Chinese - Hong Kong SAR 3 3 . , english 109 el_GR Greek - Greece 11 9 , . greek +110 rm_CH Romansh - Switzerland 9 9 , ' english diff --git a/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test index 7a2f5f3e699..0e6608fd848 100644 --- a/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test +++ b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test @@ -58,6 +58,7 @@ set @@global.debug_dbug= @old_slave_dbug; connection master; set @@global.binlog_checksum = CRC32; +--source include/wait_for_binlog_checkpoint.inc TRUNCATE t1; let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); diff --git a/mysql-test/suite/sys_vars/r/innodb_buf_flush_list_now_basic.result b/mysql-test/suite/sys_vars/r/innodb_buf_flush_list_now_basic.result new file mode 100644 index 00000000000..95b4e6fe780 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_buf_flush_list_now_basic.result @@ -0,0 +1,23 @@ +# +# Basic test for innodb_buf_flush_list_now. +# +SELECT @@global.innodb_buf_flush_list_now; +@@global.innodb_buf_flush_list_now +0 +set global innodb_buf_flush_list_now = 1; +SELECT @@global.innodb_buf_flush_list_now; +@@global.innodb_buf_flush_list_now +0 +set global innodb_buf_flush_list_now = 0; +set global innodb_buf_flush_list_now = dummy; +ERROR 42000: Variable 'innodb_buf_flush_list_now' can't be set to the value of 'dummy' +set innodb_buf_flush_list_now = ON; +ERROR HY000: Variable 'innodb_buf_flush_list_now' is a GLOBAL variable and should be set with SET GLOBAL +# Setting to ON is ok. +set global innodb_buf_flush_list_now = ON; +# Setting to OFF is ok. +set global innodb_buf_flush_list_now = OFF; +# Must always be 0. +SELECT @@global.innodb_buf_flush_list_now; +@@global.innodb_buf_flush_list_now +0 diff --git a/mysql-test/suite/sys_vars/r/innodb_status_output_basic.result b/mysql-test/suite/sys_vars/r/innodb_status_output_basic.result new file mode 100644 index 00000000000..35731a2334b --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_status_output_basic.result @@ -0,0 +1,102 @@ +SET @start_global_value = @@global.innodb_status_output; +SELECT @start_global_value; +@start_global_value +0 +Valid values are 'ON' and 'OFF' +select @@global.innodb_status_output in (0, 1); +@@global.innodb_status_output in (0, 1) +1 +select @@global.innodb_status_output; +@@global.innodb_status_output +0 +select @@session.innodb_status_output; +ERROR HY000: Variable 'innodb_status_output' is a GLOBAL variable +show global variables like 'innodb_status_output'; +Variable_name Value +innodb_status_output OFF +show session variables like 'innodb_status_output'; +Variable_name Value +innodb_status_output OFF +select * from information_schema.global_variables where variable_name='innodb_status_output'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT OFF +select * from information_schema.session_variables where variable_name='innodb_status_output'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT OFF +set global innodb_status_output='OFF'; +select @@global.innodb_status_output; +@@global.innodb_status_output +0 +select * from information_schema.global_variables where variable_name='innodb_status_output'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT OFF +select * from information_schema.session_variables where variable_name='innodb_status_output'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT OFF +set @@global.innodb_status_output=1; +select @@global.innodb_status_output; +@@global.innodb_status_output +1 +select * from information_schema.global_variables where variable_name='innodb_status_output'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT ON +select * from information_schema.session_variables where variable_name='innodb_status_output'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT ON +set global innodb_status_output=0; +select @@global.innodb_status_output; +@@global.innodb_status_output +0 +select * from information_schema.global_variables where variable_name='innodb_status_output'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT OFF +select * from information_schema.session_variables where variable_name='innodb_status_output'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT OFF +set @@global.innodb_status_output='ON'; +select @@global.innodb_status_output; +@@global.innodb_status_output +1 +select * from information_schema.global_variables where variable_name='innodb_status_output'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT ON +select * from information_schema.session_variables where variable_name='innodb_status_output'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT ON +set session innodb_status_output='OFF'; +ERROR HY000: Variable 'innodb_status_output' is a GLOBAL variable and should be set with SET GLOBAL +set @@session.innodb_status_output='ON'; +ERROR HY000: Variable 'innodb_status_output' is a GLOBAL variable and should be set with SET GLOBAL +set global innodb_status_output=1.1; +ERROR 42000: Incorrect argument type to variable 'innodb_status_output' +set global innodb_status_output=1e1; +ERROR 42000: Incorrect argument type to variable 'innodb_status_output' +set global innodb_status_output=2; +ERROR 42000: Variable 'innodb_status_output' can't be set to the value of '2' +set global innodb_status_output=-3; +ERROR 42000: Variable 'innodb_status_output' can't be set to the value of '-3' +select @@global.innodb_status_output; +@@global.innodb_status_output +1 +select * from information_schema.global_variables where variable_name='innodb_status_output'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT ON +select * from information_schema.session_variables where variable_name='innodb_status_output'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT ON +set global innodb_status_output=DEFAULT; +select @@global.innodb_status_output; +@@global.innodb_status_output +0 +select * from information_schema.global_variables where variable_name='innodb_status_output'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT OFF +select * from information_schema.session_variables where variable_name='innodb_status_output'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT OFF +set global innodb_status_output='AUTO'; +ERROR 42000: Variable 'innodb_status_output' can't be set to the value of 'AUTO' +SET @@global.innodb_status_output = @start_global_value; +SELECT @@global.innodb_status_output; +@@global.innodb_status_output +0 diff --git a/mysql-test/suite/sys_vars/r/innodb_status_output_locks_basic.result b/mysql-test/suite/sys_vars/r/innodb_status_output_locks_basic.result new file mode 100644 index 00000000000..6fc741a7975 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_status_output_locks_basic.result @@ -0,0 +1,102 @@ +SET @start_global_value = @@global.innodb_status_output_locks; +SELECT @start_global_value; +@start_global_value +0 +Valid values are 'ON' and 'OFF' +select @@global.innodb_status_output_locks in (0, 1); +@@global.innodb_status_output_locks in (0, 1) +1 +select @@global.innodb_status_output_locks; +@@global.innodb_status_output_locks +0 +select @@session.innodb_status_output_locks; +ERROR HY000: Variable 'innodb_status_output_locks' is a GLOBAL variable +show global variables like 'innodb_status_output_locks'; +Variable_name Value +innodb_status_output_locks OFF +show session variables like 'innodb_status_output_locks'; +Variable_name Value +innodb_status_output_locks OFF +select * from information_schema.global_variables where variable_name='innodb_status_output_locks'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT_LOCKS OFF +select * from information_schema.session_variables where variable_name='innodb_status_output_locks'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT_LOCKS OFF +set global innodb_status_output_locks='OFF'; +select @@global.innodb_status_output_locks; +@@global.innodb_status_output_locks +0 +select * from information_schema.global_variables where variable_name='innodb_status_output_locks'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT_LOCKS OFF +select * from information_schema.session_variables where variable_name='innodb_status_output_locks'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT_LOCKS OFF +set @@global.innodb_status_output_locks=1; +select @@global.innodb_status_output_locks; +@@global.innodb_status_output_locks +1 +select * from information_schema.global_variables where variable_name='innodb_status_output_locks'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT_LOCKS ON +select * from information_schema.session_variables where variable_name='innodb_status_output_locks'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT_LOCKS ON +set global innodb_status_output_locks=0; +select @@global.innodb_status_output_locks; +@@global.innodb_status_output_locks +0 +select * from information_schema.global_variables where variable_name='innodb_status_output_locks'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT_LOCKS OFF +select * from information_schema.session_variables where variable_name='innodb_status_output_locks'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT_LOCKS OFF +set @@global.innodb_status_output_locks='ON'; +select @@global.innodb_status_output_locks; +@@global.innodb_status_output_locks +1 +select * from information_schema.global_variables where variable_name='innodb_status_output_locks'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT_LOCKS ON +select * from information_schema.session_variables where variable_name='innodb_status_output_locks'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT_LOCKS ON +set session innodb_status_output_locks='OFF'; +ERROR HY000: Variable 'innodb_status_output_locks' is a GLOBAL variable and should be set with SET GLOBAL +set @@session.innodb_status_output_locks='ON'; +ERROR HY000: Variable 'innodb_status_output_locks' is a GLOBAL variable and should be set with SET GLOBAL +set global innodb_status_output_locks=1.1; +ERROR 42000: Incorrect argument type to variable 'innodb_status_output_locks' +set global innodb_status_output_locks=1e1; +ERROR 42000: Incorrect argument type to variable 'innodb_status_output_locks' +set global innodb_status_output_locks=2; +ERROR 42000: Variable 'innodb_status_output_locks' can't be set to the value of '2' +set global innodb_status_output_locks=-3; +ERROR 42000: Variable 'innodb_status_output_locks' can't be set to the value of '-3' +select @@global.innodb_status_output_locks; +@@global.innodb_status_output_locks +1 +select * from information_schema.global_variables where variable_name='innodb_status_output_locks'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT_LOCKS ON +select * from information_schema.session_variables where variable_name='innodb_status_output_locks'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT_LOCKS ON +set global innodb_status_output_locks=DEFAULT; +select @@global.innodb_status_output_locks; +@@global.innodb_status_output_locks +0 +select * from information_schema.global_variables where variable_name='innodb_status_output_locks'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT_LOCKS OFF +select * from information_schema.session_variables where variable_name='innodb_status_output_locks'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATUS_OUTPUT_LOCKS OFF +set global innodb_status_output_locks='AUTO'; +ERROR 42000: Variable 'innodb_status_output_locks' can't be set to the value of 'AUTO' +SET @@global.innodb_status_output_locks = @start_global_value; +SELECT @@global.innodb_status_output_locks; +@@global.innodb_status_output_locks +0 diff --git a/mysql-test/suite/sys_vars/r/lc_time_names_basic.result b/mysql-test/suite/sys_vars/r/lc_time_names_basic.result index e61436c0e47..ed03c3e6d94 100644 --- a/mysql-test/suite/sys_vars/r/lc_time_names_basic.result +++ b/mysql-test/suite/sys_vars/r/lc_time_names_basic.result @@ -1022,7 +1022,11 @@ SELECT @@lc_time_names; @@lc_time_names el_GR SET @@lc_time_names = 110; -ERROR HY000: Unknown locale: '110' +SELECT @@lc_time_names; +@@lc_time_names +rm_CH +SET @@lc_time_names = 111; +ERROR HY000: Unknown locale: '111' '#--------------------FN_DYNVARS_060_10-------------------------#' SET @@lc_time_names = en_EN; ERROR HY000: Unknown locale: 'en_EN' diff --git a/mysql-test/suite/sys_vars/t/innodb_buf_flush_list_now_basic.test b/mysql-test/suite/sys_vars/t/innodb_buf_flush_list_now_basic.test new file mode 100644 index 00000000000..8a53b0a5770 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_buf_flush_list_now_basic.test @@ -0,0 +1,32 @@ +--echo # +--echo # Basic test for innodb_buf_flush_list_now. +--echo # + +--source include/have_innodb.inc + +# The config variable is a debug variable for now +-- source include/have_debug.inc + +SELECT @@global.innodb_buf_flush_list_now; + +set global innodb_buf_flush_list_now = 1; + +SELECT @@global.innodb_buf_flush_list_now; + +set global innodb_buf_flush_list_now = 0; + +--error ER_WRONG_VALUE_FOR_VAR +set global innodb_buf_flush_list_now = dummy; + +--error ER_GLOBAL_VARIABLE +set innodb_buf_flush_list_now = ON; + +--echo # Setting to ON is ok. +set global innodb_buf_flush_list_now = ON; + +--echo # Setting to OFF is ok. +set global innodb_buf_flush_list_now = OFF; + +--echo # Must always be 0. +SELECT @@global.innodb_buf_flush_list_now; + diff --git a/mysql-test/suite/sys_vars/t/innodb_status_output_basic.test b/mysql-test/suite/sys_vars/t/innodb_status_output_basic.test new file mode 100644 index 00000000000..4459632134d --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_status_output_basic.test @@ -0,0 +1,69 @@ +--source include/have_innodb.inc + +SET @start_global_value = @@global.innodb_status_output; +SELECT @start_global_value; + +# +# exists as global only +# +--echo Valid values are 'ON' and 'OFF' +select @@global.innodb_status_output in (0, 1); +select @@global.innodb_status_output; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.innodb_status_output; +show global variables like 'innodb_status_output'; +show session variables like 'innodb_status_output'; +select * from information_schema.global_variables where variable_name='innodb_status_output'; +select * from information_schema.session_variables where variable_name='innodb_status_output'; + +# +# show that it's writable +# +set global innodb_status_output='OFF'; +select @@global.innodb_status_output; +select * from information_schema.global_variables where variable_name='innodb_status_output'; +select * from information_schema.session_variables where variable_name='innodb_status_output'; +set @@global.innodb_status_output=1; +select @@global.innodb_status_output; +select * from information_schema.global_variables where variable_name='innodb_status_output'; +select * from information_schema.session_variables where variable_name='innodb_status_output'; +set global innodb_status_output=0; +select @@global.innodb_status_output; +select * from information_schema.global_variables where variable_name='innodb_status_output'; +select * from information_schema.session_variables where variable_name='innodb_status_output'; +set @@global.innodb_status_output='ON'; +select @@global.innodb_status_output; +select * from information_schema.global_variables where variable_name='innodb_status_output'; +select * from information_schema.session_variables where variable_name='innodb_status_output'; +--error ER_GLOBAL_VARIABLE +set session innodb_status_output='OFF'; +--error ER_GLOBAL_VARIABLE +set @@session.innodb_status_output='ON'; + +# +# incorrect types +# +--error ER_WRONG_TYPE_FOR_VAR +set global innodb_status_output=1.1; +--error ER_WRONG_TYPE_FOR_VAR +set global innodb_status_output=1e1; +--error ER_WRONG_VALUE_FOR_VAR +set global innodb_status_output=2; +--error ER_WRONG_VALUE_FOR_VAR +set global innodb_status_output=-3; +select @@global.innodb_status_output; +select * from information_schema.global_variables where variable_name='innodb_status_output'; +select * from information_schema.session_variables where variable_name='innodb_status_output'; +set global innodb_status_output=DEFAULT; +select @@global.innodb_status_output; +select * from information_schema.global_variables where variable_name='innodb_status_output'; +select * from information_schema.session_variables where variable_name='innodb_status_output'; +--error ER_WRONG_VALUE_FOR_VAR +set global innodb_status_output='AUTO'; + +# +# Cleanup +# + +SET @@global.innodb_status_output = @start_global_value; +SELECT @@global.innodb_status_output; diff --git a/mysql-test/suite/sys_vars/t/innodb_status_output_locks_basic.test b/mysql-test/suite/sys_vars/t/innodb_status_output_locks_basic.test new file mode 100644 index 00000000000..92c82b2ddbf --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_status_output_locks_basic.test @@ -0,0 +1,69 @@ +--source include/have_innodb.inc + +SET @start_global_value = @@global.innodb_status_output_locks; +SELECT @start_global_value; + +# +# exists as global only +# +--echo Valid values are 'ON' and 'OFF' +select @@global.innodb_status_output_locks in (0, 1); +select @@global.innodb_status_output_locks; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.innodb_status_output_locks; +show global variables like 'innodb_status_output_locks'; +show session variables like 'innodb_status_output_locks'; +select * from information_schema.global_variables where variable_name='innodb_status_output_locks'; +select * from information_schema.session_variables where variable_name='innodb_status_output_locks'; + +# +# show that it's writable +# +set global innodb_status_output_locks='OFF'; +select @@global.innodb_status_output_locks; +select * from information_schema.global_variables where variable_name='innodb_status_output_locks'; +select * from information_schema.session_variables where variable_name='innodb_status_output_locks'; +set @@global.innodb_status_output_locks=1; +select @@global.innodb_status_output_locks; +select * from information_schema.global_variables where variable_name='innodb_status_output_locks'; +select * from information_schema.session_variables where variable_name='innodb_status_output_locks'; +set global innodb_status_output_locks=0; +select @@global.innodb_status_output_locks; +select * from information_schema.global_variables where variable_name='innodb_status_output_locks'; +select * from information_schema.session_variables where variable_name='innodb_status_output_locks'; +set @@global.innodb_status_output_locks='ON'; +select @@global.innodb_status_output_locks; +select * from information_schema.global_variables where variable_name='innodb_status_output_locks'; +select * from information_schema.session_variables where variable_name='innodb_status_output_locks'; +--error ER_GLOBAL_VARIABLE +set session innodb_status_output_locks='OFF'; +--error ER_GLOBAL_VARIABLE +set @@session.innodb_status_output_locks='ON'; + +# +# incorrect types +# +--error ER_WRONG_TYPE_FOR_VAR +set global innodb_status_output_locks=1.1; +--error ER_WRONG_TYPE_FOR_VAR +set global innodb_status_output_locks=1e1; +--error ER_WRONG_VALUE_FOR_VAR +set global innodb_status_output_locks=2; +--error ER_WRONG_VALUE_FOR_VAR +set global innodb_status_output_locks=-3; +select @@global.innodb_status_output_locks; +select * from information_schema.global_variables where variable_name='innodb_status_output_locks'; +select * from information_schema.session_variables where variable_name='innodb_status_output_locks'; +set global innodb_status_output_locks=DEFAULT; +select @@global.innodb_status_output_locks; +select * from information_schema.global_variables where variable_name='innodb_status_output_locks'; +select * from information_schema.session_variables where variable_name='innodb_status_output_locks'; +--error ER_WRONG_VALUE_FOR_VAR +set global innodb_status_output_locks='AUTO'; + +# +# Cleanup +# + +SET @@global.innodb_status_output_locks = @start_global_value; +SELECT @@global.innodb_status_output_locks; diff --git a/mysql-test/suite/sys_vars/t/lc_time_names_basic.test b/mysql-test/suite/sys_vars/t/lc_time_names_basic.test index 68ee00b6ee0..c66bdc40a02 100644 --- a/mysql-test/suite/sys_vars/t/lc_time_names_basic.test +++ b/mysql-test/suite/sys_vars/t/lc_time_names_basic.test @@ -622,8 +622,10 @@ SET @@lc_time_names = 108; SELECT @@lc_time_names; SET @@lc_time_names = 109; SELECT @@lc_time_names; ---Error ER_UNKNOWN_LOCALE SET @@lc_time_names = 110; +SELECT @@lc_time_names; +--Error ER_UNKNOWN_LOCALE +SET @@lc_time_names = 111; --echo '#--------------------FN_DYNVARS_060_10-------------------------#' ############################################################################# diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 9270b30c042..b65e634ea61 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -1190,6 +1190,52 @@ SELECT 1 FROM DUAL WHERE MINUTE(TIMEDIFF(NULL, '12:12:12')); SELECT 1 FROM DUAL WHERE SECOND(TIMEDIFF(NULL, '12:12:12')); +--echo # +--echo # MDEV-4511 Assertion `scale <= precision' fails on GROUP BY TIMEDIFF with incorrect types +--echo # +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT a FROM t1 GROUP BY TIMEDIFF('2004-06-12',a) * 1; +DROP TABLE t1; + +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT a FROM t1 GROUP BY ADDTIME(a,'10')*1; +DROP TABLE t1; + +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY SEC_TO_TIME(concat(a,'10'))*1; +DROP TABLE t1; + +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY ADDTIME(timestamp('2001-01-01 00:00:00'),CAST(a AS SIGNED)&0xF)*1; +DROP TABLE t1; + +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY STR_TO_DATE(a,concat('%Y-%m-%d.%f',if(rand(),'','')))*1; +DROP TABLE t1; + +CREATE TABLE t1 AS SELECT + STR_TO_DATE('2001-01-01', '%Y-%m-%d') AS date_only, + STR_TO_DATE('10:10:10', '%H:%i:%s') AS time_only, + STR_TO_DATE('10:10:10.123', '%H:%i:%s.%f') AS time_microsecond, + STR_TO_DATE('2001-01-01 10:10:10', '%Y-%m-%d %H:%i:%s') AS date_time, + STR_TO_DATE('2001-01-01 10:10:10.123', '%Y-%m-%d %H:%i:%s.%f') AS date_time_microsecond; +SHOW COLUMNS FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 AS SELECT + SEC_TO_TIME(1)+0.1, + SEC_TO_TIME(1.1)+0.1, + SEC_TO_TIME(1.12)+0.1, + SEC_TO_TIME(1.123456)+0.1, + SEC_TO_TIME(1.1234567)+0.1; +SHOW COLUMNS FROM t1; +DROP TABLE t1; + --echo # --echo # MDEV-4635 Crash in UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y')) --echo # diff --git a/mysql-test/t/locale.test b/mysql-test/t/locale.test index 04ac95cea06..93e347b722d 100644 --- a/mysql-test/t/locale.test +++ b/mysql-test/t/locale.test @@ -54,3 +54,60 @@ SELECT DATE_FORMAT('2001-01-05', '%w %a %W'); SELECT DATE_FORMAT('2001-01-06', '%w %a %W'); SELECT DATE_FORMAT('2001-01-07', '%w %a %W'); --echo End of 5.4 tests + + +--echo # +--echo # Start of 5.6 tests +--echo # + +--echo # +--echo # WL#5303 Romansh locale for DAYNAME, MONTHNAME, DATE_FORMAT +--echo # + +SET NAMES utf8; +SET @old_50915_lc_time_names := @@lc_time_names; +SET lc_time_names=en_US; +SELECT DATE_FORMAT('2001-01-01', '%w %a %W'); +SELECT DATE_FORMAT('2001-03-01', '%c %b %M'); +SET lc_time_names=rm_CH; +SELECT DATE_FORMAT('2001-01-01', '%w %a %W'); +SELECT DATE_FORMAT('2001-01-02', '%w %a %W'); +SELECT DATE_FORMAT('2001-01-03', '%w %a %W'); +SELECT DATE_FORMAT('2001-01-04', '%w %a %W'); +SELECT DATE_FORMAT('2001-01-05', '%w %a %W'); +SELECT DATE_FORMAT('2001-01-06', '%w %a %W'); +SELECT DATE_FORMAT('2001-01-07', '%w %a %W'); +SELECT DATE_FORMAT('2001-01-01', '%c %b %M'); +SELECT DATE_FORMAT('2001-02-01', '%c %b %M'); +SELECT DATE_FORMAT('2001-03-01', '%c %b %M'); +SELECT DATE_FORMAT('2001-04-01', '%c %b %M'); +SELECT DATE_FORMAT('2001-05-01', '%c %b %M'); +SELECT DATE_FORMAT('2001-06-01', '%c %b %M'); +SELECT DATE_FORMAT('2001-07-01', '%c %b %M'); +SELECT DATE_FORMAT('2001-08-01', '%c %b %M'); +SELECT DATE_FORMAT('2001-09-01', '%c %b %M'); +SELECT DATE_FORMAT('2001-10-01', '%c %b %M'); +SELECT DATE_FORMAT('2001-11-01', '%c %b %M'); +SELECT DATE_FORMAT('2001-12-01', '%c %b %M'); +SET lc_time_names=de_CH; +SELECT DATE_FORMAT('2001-01-06', '%w %a %W'); +SELECT DATE_FORMAT('2001-09-01', '%c %b %M'); + +# Checking AM/PM +SELECT DATE_FORMAT('2010-03-23 11:00:00','%h %p'); +SELECT DATE_FORMAT('2010-03-23 13:00:00','%h %p'); + +# Checking numeric format +SELECT format(123456789,2,'rm_CH'); + +# Checking that error messages point to en_US. +SET lc_messages=rm_CH; +--error ER_NO_SUCH_TABLE +SELECT * FROM non_existent; + +SET lc_time_names=@old_50915_lc_time_names; + + +--echo # +--echo # End of 5.6 tests +--echo # diff --git a/mysql-test/t/mysql_upgrade.test b/mysql-test/t/mysql_upgrade.test index 0261928ac08..6de81879001 100644 --- a/mysql-test/t/mysql_upgrade.test +++ b/mysql-test/t/mysql_upgrade.test @@ -131,4 +131,33 @@ let $MYSQLD_DATADIR= `select @@datadir`; # so the following command should never fail. --remove_file $MYSQLD_DATADIR/mysql_upgrade_info + +--echo # +--echo # MDEV-4332 Increase username length from 16 characters +--echo # MDEV-6068, MDEV-6178 mysql_upgrade breaks databases with long user names +--echo # + +connection default; +GRANT SELECT ON mysql.* TO very_long_user_name_number_1; +GRANT SELECT ON mysql.* TO very_long_user_name_number_2; +GRANT ALL ON *.* TO even_longer_user_name_number_3_to_test_the_grantor_and_definer_field_length@localhost WITH GRANT OPTION; +--change_user even_longer_user_name_number_3_to_test_the_grantor_and_definer_field_length + +GRANT INSERT ON mysql.user TO very_long_user_name_number_1; +GRANT INSERT ON mysql.user TO very_long_user_name_number_2; +GRANT UPDATE (User) ON mysql.db TO very_long_user_name_number_1; +GRANT UPDATE (User) ON mysql.db TO very_long_user_name_number_2; + +CREATE PROCEDURE test.pr() BEGIN END; + +--change_user root + +--replace_result $MYSQLTEST_VARDIR var +--exec $MYSQL_UPGRADE --force 2>&1 + +SELECT definer FROM mysql.proc WHERE db = 'test' AND name = 'pr'; +SELECT grantor FROM mysql.tables_priv WHERE db = 'mysql' AND table_name = 'user'; +DROP USER very_long_user_name_number_1, very_long_user_name_number_2, even_longer_user_name_number_3_to_test_the_grantor_and_definer_field_length@localhost; +DROP PROCEDURE test.pr; + --echo End of tests diff --git a/mysql-test/t/selectivity_no_engine.test b/mysql-test/t/selectivity_no_engine.test index eb6642fb5c7..87e6b629762 100644 --- a/mysql-test/t/selectivity_no_engine.test +++ b/mysql-test/t/selectivity_no_engine.test @@ -101,6 +101,66 @@ analyze table t2 persistent for all; explain extended select * from t2 where a in (1,2,3) and b in (1,2,3); drop table t2, t1; + +--echo # +--echo # MDEV-5980: EITS: if condition is used for REF access, its selectivity is still in filtered% +--echo # +create table t0(a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1(key1 int, col1 int, key(key1)); +insert into t1 select A.a, A.a from t0 A, t0 B, t0 C; + +set histogram_size=100; +set use_stat_tables='preferably'; +set optimizer_use_condition_selectivity=4; +analyze table t1 persistent for all; +--echo # 10% is ok +explain extended select * from t1 where col1=2; +--echo # Must show 100%, not 10% +explain extended select * from t1 where key1=2; +drop table t0, t1; + +--echo # MDEV-6003: EITS: ref access, keypart2=const vs keypart2=expr - inconsistent filtered% value +--echo # +create table t0(a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 ( + kp1 int, kp2 int, + filler1 char(100), + filler2 char(100), + key(kp1, kp2) +); + +insert into t1 +select + A.a, + B.a, + 'filler-data-1', + 'filler-data-2' +from t0 A, t0 B, t0 C; +set histogram_size=100; +set use_stat_tables='preferably'; +set optimizer_use_condition_selectivity=4; +analyze table t1 persistent for all; +--echo # NOTE: 10*100%, 10*100% rows is ok +explain extended select * from t0, t1 where t1.kp1=t0.a and t1.kp2=t0.a+1; + +--echo # NOTE: t0: 10*100% is ok, t1: 10*9.90% is bad. t1 should have 10*100%. +explain extended select * from t0, t1 where t1.kp1=t0.a and t1.kp2=4; +drop table t0, t1; + +--echo # +--echo # MDEV-6209: Assertion `join->best_read < double(1.79769313486231570815e+308L)' +--echo # failed in bool greedy_search with optimizer_use_condition_selectivity>1 +--echo # +SET optimizer_use_condition_selectivity = 2; + +CREATE TABLE t1 (a CHAR(6), b INT, PRIMARY KEY (a,b)) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('foo',1),('bar',2); + +SELECT * FROM t1 AS t1_1, t1 AS t1_2 WHERE NOT ( t1_1.a <> 'baz'); +DROP TABLE t1; + --echo # --echo # End of the test file --echo # diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 65109516681..e7e621081d6 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -549,11 +549,11 @@ set lc_time_names=NULL; set lc_time_names=-1; select @@lc_time_names; --echo LC_TIME_NAMES: testing locale with the last ID: -set lc_time_names=109; +set lc_time_names=110; select @@lc_time_names; --echo LC_TIME_NAMES: testing a number beyond the valid ID range: --error ER_UNKNOWN_LOCALE -set lc_time_names=110; +set lc_time_names=111; select @@lc_time_names; --echo LC_TIME_NAMES: testing that 0 is en_US: set lc_time_names=0; diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index a8e1cac2793..9d0dd0e68ac 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -201,38 +201,32 @@ parse_arguments() { fi for arg do - # the parameter after "=", or the whole $arg if no match - val=`echo "$arg" | sed -e 's;^--[^=]*=;;'` - # what's before "=", or the whole $arg if no match - optname=`echo "$arg" | sed -e 's/^\(--[^=]*\)=.*$/\1/'` - # replace "_" by "-" ; mysqld_safe must accept "_" like mysqld does. - optname_subst=`echo "$optname" | sed 's/_/-/g'` - arg=`echo $arg | sed "s/^$optname/$optname_subst/"` + val=`echo "$arg" | sed -e "s;--[^=]*=;;"` case "$arg" in - --crash-script=*) CRASH_SCRIPT="$val" ;; + --crash[-_]script=*) CRASH_SCRIPT="$val" ;; # these get passed explicitly to mysqld --basedir=*) MY_BASEDIR_VERSION="$val" ;; --datadir=*|--data=*) DATADIR="$val" ;; - --pid-file=*) pid_file="$val" ;; - --plugin-dir=*) PLUGIN_DIR="$val" ;; + --pid[-_]file=*) pid_file="$val" ;; + --plugin[-_]dir=*) PLUGIN_DIR="$val" ;; --user=*) user="$val"; SET_USER=1 ;; - --log-basename=*|--hostname=*|--loose-log-basename=*) + --log[-_]basename=*|--hostname=*|--loose[-_]log[-_]basename=*) pid_file="$val.pid"; err_log="$val.err"; ;; # these might have been set in a [mysqld_safe] section of my.cnf # they are added to mysqld command line to override settings from my.cnf - --log-error=*) err_log="$val" ;; + --log[-_]error=*) err_log="$val" ;; --port=*) mysql_tcp_port="$val" ;; --socket=*) mysql_unix_port="$val" ;; # mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])! - --core-file-size=*) core_file_size="$val" ;; + --core[-_]file[-_]size=*) core_file_size="$val" ;; --ledir=*) ledir="$val" ;; - --malloc-lib=*) set_malloc_lib "$val" ;; + --malloc[-_]lib=*) set_malloc_lib "$val" ;; --mysqld=*) MYSQLD="$val" ;; - --mysqld-version=*) + --mysqld[-_]version=*) if test -n "$val" then MYSQLD="mysqld-$val" @@ -242,16 +236,15 @@ parse_arguments() { fi ;; --nice=*) niceness="$val" ;; - --nowatch|--no-watch|--no-auto-restart) nowatch=1 ;; - --open-files-limit=*) open_files="$val" ;; - --open_files_limit=*) open_files="$val" ;; - --skip-kill-mysqld*) KILL_MYSQLD=0 ;; + --nowatch|--no[-_]watch|--no[-_]auto[-_]restart) nowatch=1 ;; + --open[-_]files[-_]limit=*) open_files="$val" ;; + --skip[-_]kill[-_]mysqld*) KILL_MYSQLD=0 ;; --syslog) want_syslog=1 ;; - --skip-syslog) want_syslog=0 ;; - --syslog-tag=*) syslog_tag="$val" ;; + --skip[-_]syslog) want_syslog=0 ;; + --syslog[-_]tag=*) syslog_tag="$val" ;; --timezone=*) TZ="$val"; export TZ; ;; - --flush-caches) flush_caches=1 ;; - --numa-interleave) numa_interleave=1 ;; + --flush[-_]caches) flush_caches=1 ;; + --numa[-_]interleave) numa_interleave=1 ;; --help) usage ;; diff --git a/sql/events.cc b/sql/events.cc index 0c0fb0d5a38..63627b21777 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -596,6 +596,8 @@ Events::drop_schema_events(THD *thd, char *db) DBUG_ENTER("Events::drop_schema_events"); DBUG_PRINT("enter", ("dropping events from %s", db)); + DBUG_ASSERT(ok_for_lower_case_names(db)); + /* Sic: no check if the scheduler is disabled or system tables are damaged, as intended. diff --git a/sql/handler.cc b/sql/handler.cc index 50044cf3cab..3cb2106a443 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1978,6 +1978,41 @@ int ha_release_temporary_latches(THD *thd) return 0; } +/** + Check if all storage engines used in transaction agree that after + rollback to savepoint it is safe to release MDL locks acquired after + savepoint creation. + + @param thd The client thread that executes the transaction. + + @return true - It is safe to release MDL locks. + false - If it is not. +*/ +bool ha_rollback_to_savepoint_can_release_mdl(THD *thd) +{ + Ha_trx_info *ha_info; + THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt : + &thd->transaction.all); + + DBUG_ENTER("ha_rollback_to_savepoint_can_release_mdl"); + + /** + Checking whether it is safe to release metadata locks after rollback to + savepoint in all the storage engines that are part of the transaction. + */ + for (ha_info= trans->ha_list; ha_info; ha_info= ha_info->next()) + { + handlerton *ht= ha_info->ht(); + DBUG_ASSERT(ht); + + if (ht->savepoint_rollback_can_release_mdl == 0 || + ht->savepoint_rollback_can_release_mdl(ht, thd) == false) + DBUG_RETURN(false); + } + + DBUG_RETURN(true); +} + int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) { int error=0; diff --git a/sql/handler.h b/sql/handler.h index 13b783b964b..0b8bd6e9ce6 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1025,6 +1025,13 @@ struct handlerton to the savepoint_set call */ int (*savepoint_rollback)(handlerton *hton, THD *thd, void *sv); + /** + Check if storage engine allows to release metadata locks which were + acquired after the savepoint if rollback to savepoint is done. + @return true - If it is safe to release MDL locks. + false - If it is not. + */ + bool (*savepoint_rollback_can_release_mdl)(handlerton *hton, THD *thd); int (*savepoint_release)(handlerton *hton, THD *thd, void *sv); /* 'all' is true if it's a real commit, that makes persistent changes @@ -4046,6 +4053,7 @@ int ha_enable_transaction(THD *thd, bool on); /* savepoints */ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv); +bool ha_rollback_to_savepoint_can_release_mdl(THD *thd); int ha_savepoint(THD *thd, SAVEPOINT *sv); int ha_release_savepoint(THD *thd, SAVEPOINT *sv); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 4d261e7a7d9..f2f5b7b1b63 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -3144,7 +3144,7 @@ void Item_func_str_to_date::fix_length_and_dec() } cached_field_type= MYSQL_TYPE_DATETIME; - decimals= NOT_FIXED_DEC; + decimals= TIME_SECOND_PART_DIGITS; if ((const_item= args[1]->const_item())) { char format_buff[64]; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 8f881487e21..29badddad8e 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -809,7 +809,7 @@ public: bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); void fix_length_and_dec() { - decimals= args[0]->decimals; + decimals= MY_MIN(args[0]->decimals, TIME_SECOND_PART_DIGITS); Item_timefunc::fix_length_and_dec(); } const char *func_name() const { return "sec_to_time"; } diff --git a/sql/lock.cc b/sql/lock.cc index 54681d25b0a..d5124ebc0f8 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -860,6 +860,8 @@ bool lock_object_name(THD *thd, MDL_key::enum_mdl_namespace mdl_type, MDL_request schema_request; MDL_request mdl_request; + DBUG_ASSERT(ok_for_lower_case_names(db)); + if (thd->locked_tables_mode) { my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, diff --git a/sql/log.cc b/sql/log.cc index 901e4e5041d..dafe89ac7f0 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -73,6 +73,8 @@ static int binlog_init(void *p); static int binlog_close_connection(handlerton *hton, THD *thd); static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv); static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv); +static bool binlog_savepoint_rollback_can_release_mdl(handlerton *hton, + THD *thd); static int binlog_commit(handlerton *hton, THD *thd, bool all); static int binlog_rollback(handlerton *hton, THD *thd, bool all); static int binlog_prepare(handlerton *hton, THD *thd, bool all); @@ -1629,6 +1631,8 @@ int binlog_init(void *p) binlog_hton->close_connection= binlog_close_connection; binlog_hton->savepoint_set= binlog_savepoint_set; binlog_hton->savepoint_rollback= binlog_savepoint_rollback; + binlog_hton->savepoint_rollback_can_release_mdl= + binlog_savepoint_rollback_can_release_mdl; binlog_hton->commit= binlog_commit; binlog_hton->rollback= binlog_rollback; binlog_hton->prepare= binlog_prepare; @@ -1879,6 +1883,32 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all) return 0; } +/* + We flush the cache wrapped in a beging/rollback if: + . aborting a single or multi-statement transaction and; + . the OPTION_KEEP_LOG is active or; + . the format is STMT and a non-trans table was updated or; + . the format is MIXED and a temporary non-trans table was + updated or; + . the format is MIXED, non-trans table was updated and + aborting a single statement transaction; +*/ +static bool trans_cannot_safely_rollback(THD *thd, bool all) +{ + binlog_cache_mngr *const cache_mngr= + (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + + return ((thd->variables.option_bits & OPTION_KEEP_LOG) || + (trans_has_updated_non_trans_table(thd) && + thd->variables.binlog_format == BINLOG_FORMAT_STMT) || + (cache_mngr->trx_cache.changes_to_non_trans_temp_table() && + thd->variables.binlog_format == BINLOG_FORMAT_MIXED) || + (trans_has_updated_non_trans_table(thd) && + ending_single_stmt_trans(thd,all) && + thd->variables.binlog_format == BINLOG_FORMAT_MIXED)); +} + + /** This function is called once after each statement. @@ -1999,25 +2029,7 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) } else if (!error) { - /* - We flush the cache wrapped in a beging/rollback if: - . aborting a single or multi-statement transaction and; - . the OPTION_KEEP_LOG is active or; - . the format is STMT and a non-trans table was updated or; - . the format is MIXED and a temporary non-trans table was - updated or; - . the format is MIXED, non-trans table was updated and - aborting a single statement transaction; - */ - if (ending_trans(thd, all) && - ((thd->variables.option_bits & OPTION_KEEP_LOG) || - (trans_has_updated_non_trans_table(thd) && - thd->variables.binlog_format == BINLOG_FORMAT_STMT) || - (cache_mngr->trx_cache.changes_to_non_trans_temp_table() && - thd->variables.binlog_format == BINLOG_FORMAT_MIXED) || - (trans_has_updated_non_trans_table(thd) && - ending_single_stmt_trans(thd,all) && - thd->variables.binlog_format == BINLOG_FORMAT_MIXED))) + if (ending_trans(thd, all) && trans_cannot_safely_rollback(thd, all)) error= binlog_rollback_flush_trx_cache(thd, all, cache_mngr); /* Truncate the cache if: @@ -2197,6 +2209,30 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) } +/** + Check whether binlog state allows to safely release MDL locks after + rollback to savepoint. + + @param hton The binlog handlerton. + @param thd The client thread that executes the transaction. + + @return true - It is safe to release MDL locks. + false - If it is not. +*/ +static bool binlog_savepoint_rollback_can_release_mdl(handlerton *hton, + THD *thd) +{ + DBUG_ENTER("binlog_savepoint_rollback_can_release_mdl"); + /* + If we have not updated any non-transactional tables rollback + to savepoint will simply truncate binlog cache starting from + SAVEPOINT command. So it should be safe to release MDL acquired + after SAVEPOINT command in this case. + */ + DBUG_RETURN(!trans_cannot_safely_rollback(thd, true)); +} + + int check_binlog_magic(IO_CACHE* log, const char** errmsg) { uchar magic[4]; diff --git a/sql/log_event.cc b/sql/log_event.cc index 0a24d45113b..6610c436302 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4153,7 +4153,8 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, (sql_mode & ~(ulong) MODE_NO_DIR_IN_CREATE)); if (charset_inited) { - if (rgi->cached_charset_compare(charset)) + rpl_sql_thread_info *sql_info= thd->system_thread_info.rpl_sql_info; + if (sql_info->cached_charset_compare(charset)) { /* Verify that we support the charsets found in the event. */ if (!(thd->variables.character_set_client= @@ -4470,18 +4471,7 @@ end: int Query_log_event::do_update_pos(rpl_group_info *rgi) { - /* - Note that we will not increment group* positions if we are just - after a SET ONE_SHOT, because SET ONE_SHOT should not be separated - from its following updating query. - */ - if (thd->one_shot_set) - { - rgi->inc_event_relay_log_pos(); - return 0; - } - else - return Log_event::do_update_pos(rgi); + return Log_event::do_update_pos(rgi); } diff --git a/sql/log_event.h b/sql/log_event.h index bba1b907a57..11cbfd191f2 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -663,7 +663,8 @@ enum Log_event_type PRE_GA_DELETE_ROWS_EVENT = 22, /* - These event numbers are used from 5.1.16 until mysql-trunk-xx + These event numbers are used from 5.1.16 until mysql-5.6.6, + and in MariaDB */ WRITE_ROWS_EVENT_V1 = 23, UPDATE_ROWS_EVENT_V1 = 24, @@ -685,11 +686,13 @@ enum Log_event_type data to the slave: data that a slave can handle in case there is code for handling it, but which can be ignored if it is not recognized. + + These mysql-5.6 events are not recognized (and ignored) by MariaDB */ IGNORABLE_LOG_EVENT= 28, ROWS_QUERY_LOG_EVENT= 29, - /* Version 2 of the Row events */ + /* Version 2 of the Row events, generated only by mysql-5.6.6+ */ WRITE_ROWS_EVENT = 30, UPDATE_ROWS_EVENT = 31, DELETE_ROWS_EVENT = 32, diff --git a/sql/mdl.cc b/sql/mdl.cc index 374a0407f78..2c2d64e96b2 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -718,6 +718,7 @@ static inline int mdl_iterate_lock(MDL_lock *lock, int mdl_iterate(int (*callback)(MDL_ticket *ticket, void *arg), void *arg) { + DYNAMIC_ARRAY locks; uint i, j; int res; DBUG_ENTER("mdl_iterate"); @@ -726,18 +727,48 @@ int mdl_iterate(int (*callback)(MDL_ticket *ticket, void *arg), void *arg) (res= mdl_iterate_lock(mdl_locks.m_commit_lock, callback, arg))) DBUG_RETURN(res); + my_init_dynamic_array(&locks, sizeof(MDL_lock*), 512, 1, MYF(0)); + for (i= 0; i < mdl_locks.m_partitions.elements(); i++) { MDL_map_partition *part= mdl_locks.m_partitions.at(i); + /* Collect all locks first */ mysql_mutex_lock(&part->m_mutex); + if (allocate_dynamic(&locks, part->m_locks.records)) + { + res= 1; + mysql_mutex_unlock(&part->m_mutex); + break; + } + reset_dynamic(&locks); for (j= 0; j < part->m_locks.records; j++) { - if ((res= mdl_iterate_lock((MDL_lock*) my_hash_element(&part->m_locks, j), - callback, arg))) - break; + MDL_lock *lock= (MDL_lock*) my_hash_element(&part->m_locks, j); + lock->m_ref_usage++; + insert_dynamic(&locks, &lock); } mysql_mutex_unlock(&part->m_mutex); + + /* Now show them */ + for (j= 0; j < locks.elements; j++) + { + MDL_lock *lock= (MDL_lock*) *dynamic_element(&locks, j, MDL_lock**); + res= mdl_iterate_lock(lock, callback, arg); + + mysql_prlock_wrlock(&lock->m_rwlock); + uint ref_usage= lock->m_ref_usage; + uint ref_release= ++lock->m_ref_release; + bool is_destroyed= lock->m_is_destroyed; + mysql_prlock_unlock(&lock->m_rwlock); + + if (unlikely(is_destroyed && ref_usage == ref_release)) + MDL_lock::destroy(lock); + + if (res) + break; + } } + delete_dynamic(&locks); DBUG_RETURN(res); } diff --git a/sql/mdl.h b/sql/mdl.h index dbd44e8c6ab..47c587eb3be 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -37,6 +37,7 @@ class THD; class MDL_context; class MDL_lock; class MDL_ticket; +bool ok_for_lower_case_names(const char *name); /** @def ENTER_COND(C, M, S, O) @@ -350,6 +351,7 @@ public: NAME_LEN) - m_ptr + 1); m_hash_value= my_hash_sort(&my_charset_bin, (uchar*) m_ptr + 1, m_length - 1); + DBUG_ASSERT(ok_for_lower_case_names(db)); } void mdl_key_init(const MDL_key *rhs) { diff --git a/sql/opt_range.cc b/sql/opt_range.cc index d4f171321e0..bfba74cf587 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -13755,15 +13755,21 @@ int QUICK_GROUP_MIN_MAX_SELECT::init() { if (group_prefix) /* Already initialized. */ return 0; - - if (!(last_prefix= (uchar*) alloc_root(&alloc, group_prefix_len))) + + /* + We allocate one byte more to serve the case when the last field in + the buffer is compared using uint3korr (e.g. a Field_newdate field) + */ + if (!(last_prefix= (uchar*) alloc_root(&alloc, group_prefix_len+1))) return 1; /* We may use group_prefix to store keys with all select fields, so allocate enough space for it. + We allocate one byte more to serve the case when the last field in + the buffer is compared using uint3korr (e.g. a Field_newdate field) */ if (!(group_prefix= (uchar*) alloc_root(&alloc, - real_prefix_len + min_max_arg_len))) + real_prefix_len+min_max_arg_len+1))) return 1; if (key_infix_len > 0) diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index a136af38356..af739b1dad4 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -216,6 +216,16 @@ public: bool stop_all_slaves(THD *thd); }; + +/* + The class rpl_io_thread_info is the THD::system_thread_info for the IO thread. +*/ +class rpl_io_thread_info +{ +public: +}; + + bool check_master_connection_name(LEX_STRING *name); void create_logfile_name_with_suffix(char *res_file_name, size_t length, const char *info_file, diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 5c902249914..e72d3470a7f 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -33,7 +33,7 @@ rpt_handle_event(rpl_parallel_thread::queued_event *qev, THD *thd= rgi->thd; thd->rgi_slave= rgi; - thd->rpl_filter = rli->mi->rpl_filter; + thd->system_thread_info.rpl_sql_info->rpl_filter = rli->mi->rpl_filter; /* ToDo: Access to thd, and what about rli, split out a parallel part? */ mysql_mutex_lock(&rli->data_lock); @@ -212,6 +212,7 @@ handle_rpl_parallel_thread(void *arg) rpl_parallel_thread::queued_event *qevs_to_free; rpl_group_info *rgis_to_free; group_commit_orderer *gcos_to_free; + rpl_sql_thread_info sql_info(NULL); size_t total_event_size; int err; @@ -242,6 +243,7 @@ handle_rpl_parallel_thread(void *arg) thd_proc_info(thd, "Waiting for work from main SQL threads"); thd->set_time(); thd->variables.lock_wait_timeout= LONG_TIMEOUT; + thd->system_thread_info.rpl_sql_info= &sql_info; /* For now, we need to run the replication parallel worker threads in READ COMMITTED. This is needed because gap locks are not symmetric. diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 8104d0ff553..a162d1d79f8 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1479,7 +1479,6 @@ rpl_group_info::rpl_group_info(Relay_log_info *rli) deferred_events(NULL), m_annotate_event(0), is_parallel_exec(false) { reinit(rli); - cached_charset_invalidate(); bzero(¤t_gtid, sizeof(current_gtid)); mysql_mutex_init(key_rpl_group_info_sleep_lock, &sleep_lock, MY_MUTEX_INIT_FAST); @@ -1562,29 +1561,6 @@ delete_or_keep_event_post_apply(rpl_group_info *rgi, } -void rpl_group_info::cached_charset_invalidate() -{ - DBUG_ENTER("rpl_group_info::cached_charset_invalidate"); - - /* Full of zeroes means uninitialized. */ - bzero(cached_charset, sizeof(cached_charset)); - DBUG_VOID_RETURN; -} - - -bool rpl_group_info::cached_charset_compare(char *charset) const -{ - DBUG_ENTER("rpl_group_info::cached_charset_compare"); - - if (memcmp(cached_charset, charset, sizeof(cached_charset))) - { - memcpy(const_cast(cached_charset), charset, sizeof(cached_charset)); - DBUG_RETURN(1); - } - DBUG_RETURN(0); -} - - void rpl_group_info::cleanup_context(THD *thd, bool error) { DBUG_ENTER("Relay_log_info::cleanup_context"); @@ -1769,4 +1745,33 @@ rpl_group_info::mark_start_commit() } +rpl_sql_thread_info::rpl_sql_thread_info(Rpl_filter *filter) + : rpl_filter(filter) +{ + cached_charset_invalidate(); +} + + +void rpl_sql_thread_info::cached_charset_invalidate() +{ + DBUG_ENTER("rpl_group_info::cached_charset_invalidate"); + + /* Full of zeroes means uninitialized. */ + bzero(cached_charset, sizeof(cached_charset)); + DBUG_VOID_RETURN; +} + + +bool rpl_sql_thread_info::cached_charset_compare(char *charset) const +{ + DBUG_ENTER("rpl_group_info::cached_charset_compare"); + + if (memcmp(cached_charset, charset, sizeof(cached_charset))) + { + memcpy(const_cast(cached_charset), charset, sizeof(cached_charset)); + DBUG_RETURN(1); + } + DBUG_RETURN(0); +} + #endif diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index bcb237b6ced..137571ab820 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -26,6 +26,7 @@ struct RPL_TABLE_LIST; class Master_info; +class Rpl_filter; /**************************************************************************** @@ -536,8 +537,6 @@ struct rpl_group_info mysql_mutex_t sleep_lock; mysql_cond_t sleep_cond; - char cached_charset[6]; - /* trans_retries varies between 0 to slave_transaction_retries and counts how many times the slave has retried the present transaction; gets reset to 0 @@ -671,15 +670,6 @@ struct rpl_group_info return false; } - /* - Last charset (6 bytes) seen by slave SQL thread is cached here; it helps - the thread save 3 get_charset() per Query_log_event if the charset is not - changing from event to event (common situation). - When the 6 bytes are equal to 0 is used to mean "cache is invalidated". - */ - void cached_charset_invalidate(); - bool cached_charset_compare(char *charset) const; - void clear_tables_to_lock(); void cleanup_context(THD *, bool); void slave_close_thread_tables(THD *); @@ -727,6 +717,30 @@ struct rpl_group_info }; +/* + The class rpl_sql_thread_info is the THD::system_thread_info for an SQL + thread; this is either the driver SQL thread or a worker thread for parallel + replication. +*/ +class rpl_sql_thread_info +{ +public: + char cached_charset[6]; + Rpl_filter* rpl_filter; + + rpl_sql_thread_info(Rpl_filter *filter); + + /* + Last charset (6 bytes) seen by slave SQL thread is cached here; it helps + the thread save 3 get_charset() per Query_log_event if the charset is not + changing from event to event (common situation). + When the 6 bytes are equal to 0 is used to mean "cache is invalidated". + */ + void cached_charset_invalidate(); + bool cached_charset_compare(char *charset) const; +}; + + // Defined in rpl_rli.cc int init_relay_log_info(Relay_log_info* rli, const char* info_fname); diff --git a/sql/slave.cc b/sql/slave.cc index b5d8758a405..a40e5735b24 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2891,7 +2891,7 @@ void set_slave_thread_default_charset(THD* thd, rpl_group_info *rgi) global_system_variables.collation_server; thd->update_charset(); - rgi->cached_charset_invalidate(); + thd->system_thread_info.rpl_sql_info->cached_charset_invalidate(); DBUG_VOID_RETURN; } @@ -3768,6 +3768,7 @@ pthread_handler_t handle_slave_io(void *arg) uint retry_count; bool suppress_warnings; int ret; + rpl_io_thread_info io_info; #ifndef DBUG_OFF uint retry_count_reg= 0, retry_count_dump= 0, retry_count_event= 0; #endif @@ -3801,6 +3802,7 @@ pthread_handler_t handle_slave_io(void *arg) sql_print_error("Failed during slave I/O thread initialization"); goto err_during_init; } + thd->system_thread_info.rpl_io_info= &io_info; mysql_mutex_lock(&LOCK_thread_count); threads.append(thd); mysql_mutex_unlock(&LOCK_thread_count); @@ -4367,6 +4369,7 @@ pthread_handler_t handle_slave_sql(void *arg) Relay_log_info* rli = &mi->rli; const char *errmsg; rpl_group_info *serial_rgi; + rpl_sql_thread_info sql_info(mi->rpl_filter); // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff my_thread_init(); @@ -4378,7 +4381,7 @@ pthread_handler_t handle_slave_sql(void *arg) serial_rgi= new rpl_group_info(rli); thd = new THD; // note that contructor of THD uses DBUG_ ! thd->thread_stack = (char*)&thd; // remember where our stack is - thd->rpl_filter = mi->rpl_filter; + thd->system_thread_info.rpl_sql_info= &sql_info; DBUG_ASSERT(rli->inited); DBUG_ASSERT(rli->mi == mi); @@ -4676,7 +4679,7 @@ err_during_init: mysql_cond_broadcast(&rli->data_cond); rli->ignore_log_space_limit= 0; /* don't need any lock */ /* we die so won't remember charset - re-update them on next thread start */ - serial_rgi->cached_charset_invalidate(); + thd->system_thread_info.rpl_sql_info->cached_charset_invalidate(); /* TODO: see if we can do this conditionally in next_event() instead diff --git a/sql/sp.cc b/sql/sp.cc index 6ad38956cee..188b311ae86 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1437,6 +1437,8 @@ bool lock_db_routines(THD *thd, char *db) uchar keybuf[MAX_KEY_LENGTH]; DBUG_ENTER("lock_db_routines"); + DBUG_ASSERT(ok_for_lower_case_names(db)); + /* mysql.proc will be re-opened during deletion, so we can ignore errors when opening the table here. The error handler is diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 92f7ac020f5..89248f5746b 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -493,6 +493,7 @@ sp_name::init_qname(THD *thd) (int) m_db.length, (m_db.length ? m_db.str : ""), dot, ".", (int) m_name.length, m_name.str); + DBUG_ASSERT(ok_for_lower_case_names(m_db.str)); } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 130113c17f1..c4c06ba0e0b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -38,6 +38,7 @@ #include "records.h" // READ_RECORD, read_record_info, // init_read_record, end_read_record #include "rpl_filter.h" // rpl_filter +#include "rpl_rli.h" #include #include #include "sp_head.h" @@ -2558,7 +2559,7 @@ bool change_password(THD *thd, const char *host, const char *user, { TABLE_LIST tables; TABLE *table; - Rpl_filter *rpl_filter= thd->rpl_filter; + Rpl_filter *rpl_filter; /* Buffer should be extended when password length is extended. */ char buff[512]; ulong query_length; @@ -2580,7 +2581,8 @@ bool change_password(THD *thd, const char *host, const char *user, GRANT and REVOKE are applied the slave in/exclusion rules as they are some kind of updates to the mysql.% tables. */ - if (thd->slave_thread && rpl_filter->is_on()) + if (thd->slave_thread && + (rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter)->is_on()) { /* The tables must be marked "updating" so that tables_ok() takes them into @@ -5393,7 +5395,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, TABLE_LIST tables[3]; bool create_new_users=0; char *db_name, *table_name; - Rpl_filter *rpl_filter= thd->rpl_filter; + Rpl_filter *rpl_filter; DBUG_ENTER("mysql_table_grant"); if (!initialized) @@ -5483,7 +5485,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, GRANT and REVOKE are applied the slave in/exclusion rules as they are some kind of updates to the mysql.% tables. */ - if (thd->slave_thread && rpl_filter->is_on()) + if (thd->slave_thread && + (rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter)->is_on()) { /* The tables must be marked "updating" so that tables_ok() takes them into @@ -5670,7 +5673,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, TABLE_LIST tables[2]; bool create_new_users=0, result=0; char *db_name, *table_name; - Rpl_filter *rpl_filter= thd->rpl_filter; + Rpl_filter *rpl_filter; DBUG_ENTER("mysql_routine_grant"); if (!initialized) @@ -5705,7 +5708,8 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, GRANT and REVOKE are applied the slave in/exclusion rules as they are some kind of updates to the mysql.% tables. */ - if (thd->slave_thread && rpl_filter->is_on()) + if (thd->slave_thread && + (rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter)->is_on()) { /* The tables must be marked "updating" so that tables_ok() takes them into @@ -6141,7 +6145,7 @@ bool mysql_grant(THD *thd, const char *db, List &list, char tmp_db[SAFE_NAME_LEN+1]; bool create_new_users=0; TABLE_LIST tables[2]; - Rpl_filter *rpl_filter= thd->rpl_filter; + Rpl_filter *rpl_filter; DBUG_ENTER("mysql_grant"); if (!initialized) @@ -6190,7 +6194,8 @@ bool mysql_grant(THD *thd, const char *db, List &list, GRANT and REVOKE are applied the slave in/exclusion rules as they are some kind of updates to the mysql.% tables. */ - if (thd->slave_thread && rpl_filter->is_on()) + if (thd->slave_thread && + (rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter)->is_on()) { /* The tables must be marked "updating" so that tables_ok() takes them into @@ -8223,7 +8228,7 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc) #define GRANT_TABLES 7 static int open_grant_tables(THD *thd, TABLE_LIST *tables) { - Rpl_filter *rpl_filter= thd->rpl_filter; + Rpl_filter *rpl_filter; DBUG_ENTER("open_grant_tables"); if (!initialized) @@ -8267,7 +8272,8 @@ static int open_grant_tables(THD *thd, TABLE_LIST *tables) GRANT and REVOKE are applied the slave in/exclusion rules as they are some kind of updates to the mysql.% tables. */ - if (thd->slave_thread && rpl_filter->is_on()) + if (thd->slave_thread && + (rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter)->is_on()) { /* The tables must be marked "updating" so that tables_ok() takes them into diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index c6c5418e0cf..cf68ba36997 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -2306,6 +2306,8 @@ void Query_cache::invalidate(THD *thd, char *db) if (is_disabled()) DBUG_VOID_RETURN; + DBUG_ASSERT(ok_for_lower_case_names(db)); + bool restart= FALSE; /* Lock the query cache and queue all invalidation attempts to avoid diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 65499675455..c1c252955aa 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -956,7 +956,6 @@ THD::THD() connection_name.length= 0; bzero(&variables, sizeof(variables)); - one_shot_set= 0; file_id = 0; query_id= 0; query_name_consts= 0; diff --git a/sql/sql_class.h b/sql/sql_class.h index d050a7b3704..1c11c2f6416 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -72,6 +72,8 @@ class Parser_state; class Rows_log_event; class Sroutine_hash_entry; class user_var_entry; +class rpl_io_thread_info; +class rpl_sql_thread_info; enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME }; enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_UPDATE }; @@ -1810,8 +1812,10 @@ public: /* Slave applier execution context */ rpl_group_info* rgi_slave; - /* Used to SLAVE SQL thread */ - Rpl_filter* rpl_filter; + union { + rpl_io_thread_info *rpl_io_info; + rpl_sql_thread_info *rpl_sql_info; + } system_thread_info; void reset_for_next_command(); /* @@ -2588,7 +2592,7 @@ public: char default_master_connection_buff[MAX_CONNECTION_NAME+1]; uint8 password; /* 0, 1 or 2 */ uint8 failed_com_change_user; - bool slave_thread, one_shot_set; + bool slave_thread; bool extra_port; /* If extra connection */ bool no_errors; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 13cbcdd9f08..76288e94c75 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2468,7 +2468,7 @@ struct LEX: public Query_tables_list uint16 create_view_algorithm; uint8 create_view_check; uint8 context_analysis_only; - bool drop_temporary, local_file, one_shot_set; + bool drop_temporary, local_file; bool check_exists; bool autocommit; bool verbose, no_write_to_binlog; diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index b2b112ed4ba..c7d21ffd424 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -3247,6 +3247,75 @@ MY_LOCALE my_locale_el_GR ); /***** LOCALE END el_GR *****/ + +/***** LOCALE BEGIN rm_CH: Romansh - Switzerland *****/ +static const char *my_locale_month_names_rm_CH[13]= +{ + "schaner", "favrer", "mars", "avrigl", "matg", "zercladur", + "fanadur", "avust", "settember", "october", "november", "december", NullS +}; + +static const char *my_locale_ab_month_names_rm_CH[13]= +{ + "schan", "favr", "mars", "avr", "matg", "zercl", + "fan", "avust", "sett", "oct", "nov", "dec", NullS +}; + +static const char *my_locale_day_names_rm_CH[8]= +{ + "glindesdi", "mardi", "mesemna", "gievgia", + "venderdi", "sonda", "dumengia", NullS +}; + +static const char *my_locale_ab_day_names_rm_CH[8]= +{ + "gli", "ma", "me", "gie", "ve", "so", "du", NullS +}; + +static TYPELIB my_locale_typelib_month_names_rm_CH= +{ + array_elements(my_locale_month_names_rm_CH) - 1, + "", my_locale_month_names_rm_CH, NULL +}; + +static TYPELIB my_locale_typelib_ab_month_names_rm_CH= +{ + array_elements(my_locale_ab_month_names_rm_CH) - 1, + "", my_locale_ab_month_names_rm_CH, NULL +}; + +static TYPELIB my_locale_typelib_day_names_rm_CH= +{ + array_elements(my_locale_day_names_rm_CH) - 1, + "", my_locale_day_names_rm_CH, NULL +}; + +static TYPELIB my_locale_typelib_ab_day_names_rm_CH= +{ + array_elements(my_locale_ab_day_names_rm_CH) - 1, + "", my_locale_ab_day_names_rm_CH, NULL +}; + +MY_LOCALE my_locale_rm_CH +( + 110, + "rm_CH", + "Romansh - Switzerland", + FALSE, + &my_locale_typelib_month_names_rm_CH, + &my_locale_typelib_ab_month_names_rm_CH, + &my_locale_typelib_day_names_rm_CH, + &my_locale_typelib_ab_day_names_rm_CH, + 9, /* max mon name length */ + 9, /* max day name length */ + ',', /* decimal point rm_CH */ + '\'', /* thousands_sep rm_CH */ + "\x03\x03", /* grouping rm_CH */ + &global_errmsgs[en_US] +); +/***** LOCALE END rm_CH *****/ + + /* The list of all locales. Note, locales must be ordered according to their @@ -3365,6 +3434,7 @@ MY_LOCALE *my_locales[]= &my_locale_sv_FI, &my_locale_zh_HK, &my_locale_el_GR, + &my_locale_rm_CH, NULL }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 055317f0445..0c4983e540d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -171,8 +171,9 @@ const char *xa_state_names[]={ */ inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) { - return thd->rpl_filter->is_on() && tables && !thd->spcont && - !thd->rpl_filter->tables_ok(thd->db, tables); + Rpl_filter *rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; + return rpl_filter->is_on() && tables && !thd->spcont && + !rpl_filter->tables_ok(thd->db, tables); } #endif @@ -2030,23 +2031,6 @@ bool alloc_query(THD *thd, const char *packet, uint packet_length) return FALSE; } -static void reset_one_shot_variables(THD *thd) -{ - thd->variables.character_set_client= - global_system_variables.character_set_client; - thd->variables.collation_connection= - global_system_variables.collation_connection; - thd->variables.collation_database= - global_system_variables.collation_database; - thd->variables.collation_server= - global_system_variables.collation_server; - thd->update_charset(); - thd->variables.time_zone= - global_system_variables.time_zone; - thd->variables.lc_time_names= &my_locale_en_US; - thd->one_shot_set= 0; -} - bool sp_process_definer(THD *thd) { @@ -2233,7 +2217,7 @@ mysql_execute_command(THD *thd) /* have table map for update for multi-update statement (BUG#37051) */ bool have_table_map_for_update= FALSE; /* */ - Rpl_filter *rpl_filter= thd->rpl_filter; + Rpl_filter *rpl_filter; #endif DBUG_ENTER("mysql_execute_command"); @@ -2347,9 +2331,6 @@ mysql_execute_command(THD *thd) { /* we warn the slave SQL thread */ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); - if (thd->one_shot_set) - reset_one_shot_variables(thd); - DBUG_RETURN(0); } for (table=all_tables; table; table=table->next_global) @@ -2377,23 +2358,6 @@ mysql_execute_command(THD *thd) { /* we warn the slave SQL thread */ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); - if (thd->one_shot_set) - { - /* - It's ok to check thd->one_shot_set here: - - The charsets in a MySQL 5.0 slave can change by both a binlogged - SET ONE_SHOT statement and the event-internal charset setting, - and these two ways to change charsets do not seems to work - together. - - At least there seems to be problems in the rli cache for - charsets if we are using ONE_SHOT. Note that this is normally no - problem because either the >= 5.0 slave reads a 4.1 binlog (with - ONE_SHOT) *or* or 5.0 binlog (without ONE_SHOT) but never both." - */ - reset_one_shot_variables(thd); - } DBUG_RETURN(0); } /* @@ -3781,11 +3745,6 @@ end_with_restore_list: goto error; if (!(res= sql_set_variables(thd, lex_var_list))) { - /* - If the previous command was a SET ONE_SHOT, we don't want to forget - about the ONE_SHOT property of that SET. So we use a |= instead of = . - */ - thd->one_shot_set|= lex->one_shot_set; my_ok(thd); } else @@ -3885,12 +3844,15 @@ end_with_restore_list: above was not called. So we have to check rules again here. */ #ifdef HAVE_REPLICATION - if (thd->slave_thread && - (!rpl_filter->db_ok(lex->name.str) || - !rpl_filter->db_ok_with_wild_table(lex->name.str))) + if (thd->slave_thread) { - my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); - break; + rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; + if (!rpl_filter->db_ok(lex->name.str) || + !rpl_filter->db_ok_with_wild_table(lex->name.str)) + { + my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); + break; + } } #endif if (check_access(thd, CREATE_ACL, lex->name.str, NULL, NULL, 1, 0)) @@ -3913,12 +3875,15 @@ end_with_restore_list: above was not called. So we have to check rules again here. */ #ifdef HAVE_REPLICATION - if (thd->slave_thread && - (!rpl_filter->db_ok(lex->name.str) || - !rpl_filter->db_ok_with_wild_table(lex->name.str))) + if (thd->slave_thread) { - my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); - break; + rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; + if (!rpl_filter->db_ok(lex->name.str) || + !rpl_filter->db_ok_with_wild_table(lex->name.str)) + { + my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); + break; + } } #endif if (check_access(thd, DROP_ACL, lex->name.str, NULL, NULL, 1, 0)) @@ -3930,13 +3895,16 @@ end_with_restore_list: { LEX_STRING *db= & lex->name; #ifdef HAVE_REPLICATION - if (thd->slave_thread && - (!rpl_filter->db_ok(db->str) || - !rpl_filter->db_ok_with_wild_table(db->str))) + if (thd->slave_thread) { - res= 1; - my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); - break; + rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; + if (!rpl_filter->db_ok(db->str) || + !rpl_filter->db_ok_with_wild_table(db->str)) + { + res= 1; + my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); + break; + } } #endif if (check_db_name(db)) @@ -3973,12 +3941,15 @@ end_with_restore_list: above was not called. So we have to check rules again here. */ #ifdef HAVE_REPLICATION - if (thd->slave_thread && - (!rpl_filter->db_ok(db->str) || - !rpl_filter->db_ok_with_wild_table(db->str))) + if (thd->slave_thread) { - my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); - break; + rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; + if (!rpl_filter->db_ok(db->str) || + !rpl_filter->db_ok_with_wild_table(db->str)) + { + my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); + break; + } } #endif if (check_access(thd, ALTER_ACL, db->str, NULL, NULL, 1, 0)) @@ -5119,19 +5090,6 @@ create_sp_error: THD_STAGE_INFO(thd, stage_query_end); thd->update_stats(); - /* - Binlog-related cleanup: - Reset system variables temporarily modified by SET ONE SHOT. - - Exception: If this is a SET, do nothing. This is to allow - mysqlbinlog to print many SET commands (in this case we want the - charset temp setting to live until the real query). This is also - needed so that SET CHARACTER_SET_CLIENT... does not cancel itself - immediately. - */ - if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION) - reset_one_shot_variables(thd); - goto finish; error: diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 235de14c466..7d69a85a273 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7287,18 +7287,77 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, if (pos->key != 0) { /* - A ref access or hash join is used for this table. + A ref access or hash join is used for this table. ref access is created + from - It could have some parts with "t.key_part=const". Using ref access - means that we will only get records where the condition holds, so we - should remove its selectivity from the condition selectivity. + tbl.keypart1=expr1 AND tbl.keypart2=expr2 AND ... + and it will only return rows for which this condition is satisified. + Suppose, certain expr{i} is a constant. Since ref access only returns + rows that satisfy + + tbl.keypart{i}=const (*) + + then selectivity of this equality should not be counted in return value + of this function. This function uses the value of + + table->cond_selectivity=selectivity(COND(tbl)) (**) + + as a starting point. This value includes selectivity of equality (*). We + should somehow discount it. + + Looking at calculate_cond_selectivity_for_table(), one can see that that + the value is not necessarily a direct multiplicand in + table->cond_selectivity + + There are three possible ways to discount + 1. There is a potential range access on t.keypart{i}=const. + (an important special case: the used ref access has a const prefix for + which a range estimate is available) + + 2. The field has a histogram. field[x]->cond_selectivity has the data. + + 3. Use index stats on this index: + rec_per_key[key_part+1]/rec_per_key[key_part] + (TODO: more details about the "t.key=othertable.col" case) */ KEYUSE *keyuse= pos->key; KEYUSE *prev_ref_keyuse= keyuse; uint key= keyuse->key; - do + + /* + Check if we have a prefix of key=const that matches a quick select. + */ + if (!is_hash_join_key_no(key)) + { + table_map quick_key_map= (table_map(1) << table->quick_key_parts[key]) - 1; + if (table->quick_rows[key] && + !(quick_key_map & ~table->const_key_parts[key])) + { + /* + Ok, there is an equality for each of the key parts used by the + quick select. This means, quick select's estimate can be reused to + discount the selectivity of a prefix of a ref access. + */ + for (; quick_key_map & 1 ; quick_key_map>>= 1) + { + while (keyuse->table == table && keyuse->key == key && + keyuse->keypart == keyparts) + { + keyuse++; + } + keyparts++; + } + sel /= (double)table->quick_rows[key] / (double) table->stat_records(); + } + } + + /* + Go through the "keypart{N}=..." equalities and find those that were + already taken into account in table->cond_selectivity. + */ + while (keyuse->table == table && keyuse->key == key) { if (!(keyuse->used_tables & (rem_tables | table->map))) { @@ -7312,22 +7371,35 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, else { if (keyparts == keyuse->keypart && - !(~(keyuse->val->used_tables()) & pos->ref_depend_map) && + !((keyuse->val->used_tables()) & ~pos->ref_depend_map) && !(found_part_ref_or_null & keyuse->optimize)) { + /* Found a KEYUSE object that will be used by ref access */ keyparts++; found_part_ref_or_null|= keyuse->optimize & ~KEY_OPTIMIZE_EQ; } } + if (keyparts > keyuse->keypart) { + /* Ok this is the keyuse that will be used for ref access */ uint fldno; if (is_hash_join_key_no(key)) fldno= keyuse->keypart; else fldno= table->key_info[key].key_part[keyparts-1].fieldnr - 1; if (keyuse->val->const_item()) - sel*= table->field[fldno]->cond_selectivity; + { + sel /= table->field[fldno]->cond_selectivity; + /* + TODO: we could do better here: + 1. cond_selectivity might be =1 (the default) because quick + select on some index prevented us from analyzing + histogram for this column. + 2. we could get an estimate through this? + rec_per_key[key_part-1] / rec_per_key[key_part] + */ + } if (keyparts > 1) { ref_keyuse_steps[keyparts-2]= keyuse - prev_ref_keyuse; @@ -7337,7 +7409,7 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, } } keyuse++; - } while (keyuse->table == table && keyuse->key == key); + } } else { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index dec010bb24f..502f1b30e8f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7239,6 +7239,9 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, if (!(used_fields & HA_CREATE_USED_TRANSACTIONAL)) create_info->transactional= table->s->transactional; + if (!(used_fields & HA_CREATE_USED_CONNECTION)) + create_info->connect_string= table->s->connect_string; + restore_record(table, s->default_values); // Empty record for DEFAULT if ((create_info->fields_option_struct= (ha_field_option_struct**) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ceb4e247848..5da781f4bf5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -810,7 +810,6 @@ static void sp_create_assignment_lex(THD *thd, bool no_lookahead) lex->sql_command= SQLCOM_SET_OPTION; mysql_init_select(lex); lex->var_list.empty(); - lex->one_shot_set= 0; lex->autocommit= 0; /* get_ptr() is only correct with no lookahead. */ DBUG_ASSERT(no_lookahead); @@ -11305,7 +11304,10 @@ opt_limit_clause: limit_clause: LIMIT limit_options { - Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); + SELECT_LEX *sel= Select; + if (!sel->select_limit->basic_const_item() || + sel->select_limit->val_int() > 0) + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); } | LIMIT limit_options ROWS_SYM EXAMINED_SYM limit_rows_option { @@ -14421,7 +14423,6 @@ set: mysql_init_select(lex); lex->option_type=OPT_SESSION; lex->var_list.empty(); - lex->one_shot_set= 0; lex->autocommit= 0; sp_create_assignment_lex(thd, yychar == YYEMPTY); } diff --git a/sql/table.cc b/sql/table.cc index 210a9246a16..5da15dab9e7 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3436,6 +3436,24 @@ uint calculate_key_len(TABLE *table, uint key, const uchar *buf, return length; } +#ifndef DBUG_OFF +/** + Verifies that database/table name is in lowercase, when it should be + + This is supposed to be used only inside DBUG_ASSERT() +*/ +bool ok_for_lower_case_names(const char *name) +{ + if (!lower_case_table_names || !name) + return true; + + char buf[SAFE_NAME_LEN]; + strmake_buf(buf, name); + my_casedn_str(files_charset_info, buf); + return strcmp(name, buf) == 0; +} +#endif + /* Check if database name is valid diff --git a/sql/table.h b/sql/table.h index 975f79fc02d..f23e678697c 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2511,6 +2511,8 @@ static inline void dbug_tmp_restore_column_maps(MY_BITMAP *read_set, #endif } +bool ok_for_lower_case_names(const char *names); + enum get_table_share_flags { GTS_TABLE = 1, GTS_VIEW = 2, diff --git a/sql/transaction.cc b/sql/transaction.cc index 3575ff52e66..933e39ae357 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -574,6 +574,32 @@ bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name) DBUG_RETURN(TRUE); } + /** + Checking whether it is safe to release metadata locks acquired after + savepoint, if rollback to savepoint is successful. + + Whether it is safe to release MDL after rollback to savepoint depends + on storage engines participating in transaction: + + - InnoDB doesn't release any row-locks on rollback to savepoint so it + is probably a bad idea to release MDL as well. + - Binary log implementation in some cases (e.g when non-transactional + tables involved) may choose not to remove events added after savepoint + from transactional cache, but instead will write them to binary + log accompanied with ROLLBACK TO SAVEPOINT statement. Since the real + write happens at the end of transaction releasing MDL on tables + mentioned in these events (i.e. acquired after savepoint and before + rollback ot it) can break replication, as concurrent DROP TABLES + statements will be able to drop these tables before events will get + into binary log, + + For backward-compatibility reasons we always release MDL if binary + logging is off. + */ + bool mdl_can_safely_rollback_to_savepoint= + (!(mysql_bin_log.is_open() && thd->variables.sql_log_bin) || + ha_rollback_to_savepoint_can_release_mdl(thd)); + if (ha_rollback_to_savepoint(thd, sv)) res= TRUE; else if (((thd->variables.option_bits & OPTION_KEEP_LOG) || @@ -585,14 +611,7 @@ bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name) thd->transaction.savepoints= sv; - /* - Release metadata locks that were acquired during this savepoint unit - unless binlogging is on. Releasing locks with binlogging on can break - replication as it allows other connections to drop these tables before - rollback to savepoint is written to the binlog. - */ - bool binlog_on= mysql_bin_log.is_open() && thd->variables.sql_log_bin; - if (!res && !binlog_on) + if (!res && mdl_can_safely_rollback_to_savepoint) thd->mdl_context.rollback_to_savepoint(sv->mdl_savepoint); DBUG_RETURN(MY_TEST(res)); diff --git a/sql/unireg.cc b/sql/unireg.cc index aeeba6f4f85..b7ac8b17c38 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -46,9 +46,14 @@ static bool pack_fields(uchar *, List &, ulong); static size_t packed_fields_length(List &); static bool make_empty_rec(THD *, uchar *, uint, List &, uint, ulong); +/* + write the length as + if ( 0 < length <= 255) one byte + if (256 < length <= 65535) zero byte, then two bytes, low-endian +*/ static uchar *extra2_write_len(uchar *pos, size_t len) { - if (len < 255) + if (len <= 255) *pos++= len; else { diff --git a/storage/connect/mysql-test/connect/r/mysql.result b/storage/connect/mysql-test/connect/r/mysql.result index 51ec571486f..fc2fe2418cf 100644 --- a/storage/connect/mysql-test/connect/r/mysql.result +++ b/storage/connect/mysql-test/connect/r/mysql.result @@ -273,3 +273,26 @@ a b c d e 255 65535 4294967295 18446744073709551615 Hello DROP TABLE t2; DROP TABLE t1; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (10),(20),(30); +CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@localhost:PORT/test/t1'; +SELECT * FROM t2; +a +10 +20 +30 +ALTER TABLE t2 MODIFY a TINYINT; +Warnings: +Warning 1105 This is an outward table, table data were not modified. +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` tinyint(4) DEFAULT NULL +) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@localhost:PORT/test/t1' `TABLE_TYPE`='MYSQL' +SELECT * FROM t2; +a +10 +20 +30 +DROP TABLE t2; +DROP TABLE t1; diff --git a/storage/connect/mysql-test/connect/t/mysql.test b/storage/connect/mysql-test/connect/t/mysql.test index bcba0db753d..e245587e562 100644 --- a/storage/connect/mysql-test/connect/t/mysql.test +++ b/storage/connect/mysql-test/connect/t/mysql.test @@ -454,3 +454,19 @@ SELECT * FROM t2; DROP TABLE t2; DROP TABLE t1; + +# +# MDEV-6085 ALTER TABLE looses the connection string +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (10),(20),(30); +--replace_result $PORT PORT +--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@localhost:$PORT/test/t1' +SELECT * FROM t2; +ALTER TABLE t2 MODIFY a TINYINT; +--replace_result $PORT PORT +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t2; +DROP TABLE t1; + diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index 8210115fb82..50fdb36495d 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -391,6 +391,16 @@ IF(WITH_INNODB) SET(WITH_INNOBASE_STORAGE_ENGINE TRUE) ENDIF() +# On solaris, reduce symbol visibility, so loader does not mix +# the same symbols from builtin innodb and from shared one. +# Only required for old GCC (3.4.3) that does not support hidden visibility +IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_COMPILER_IS_GNUCC + AND NOT HAVE_VISIBILITY_HIDDEN) + SET(LINKER_SCRIPT "-Wl,-M${CMAKE_CURRENT_SOURCE_DIR}/plugin_exports") +ELSE() + SET(LINKER_SCRIPT) +ENDIF() + MYSQL_ADD_PLUGIN(innobase ${INNOBASE_SOURCES} STORAGE_ENGINE MODULE_ONLY MODULE_OUTPUT_NAME ha_innodb diff --git a/storage/innobase/api/api0api.cc b/storage/innobase/api/api0api.cc index d2f1a468f25..c5299156d7a 100644 --- a/storage/innobase/api/api0api.cc +++ b/storage/innobase/api/api0api.cc @@ -3870,6 +3870,7 @@ ib_table_truncate( ib_err_t trunc_err; ib_trx_t ib_trx = NULL; ib_crsr_t ib_crsr = NULL; + ib_ulint_t memcached_sync = 0; ib_trx = ib_trx_begin(IB_TRX_SERIALIZABLE, true, false); @@ -3885,6 +3886,13 @@ ib_table_truncate( err = DB_TABLE_NOT_FOUND; } + /* Remember the memcached_sync_count and set it to 0, so the + truncate can be executed. */ + if (table != NULL && err == DB_SUCCESS) { + memcached_sync = table->memcached_sync_count; + table->memcached_sync_count = 0; + } + dict_mutex_exit_for_mysql(); if (err == DB_SUCCESS) { @@ -3910,6 +3918,15 @@ ib_table_truncate( ut_a(err == DB_SUCCESS); } + /* Set the memcached_sync_count back. */ + if (table != NULL && memcached_sync != 0) { + dict_mutex_enter_for_mysql(); + + table->memcached_sync_count = memcached_sync; + + dict_mutex_exit_for_mysql(); + } + return(trunc_err); } @@ -3972,3 +3989,51 @@ ib_cfg_get_cfg() return(cfg_status); } + +/*****************************************************************//** +Increase/decrease the memcached sync count of table to sync memcached +DML with SQL DDLs. +@return DB_SUCCESS or error number */ +UNIV_INTERN +ib_err_t +ib_cursor_set_memcached_sync( +/*=========================*/ + ib_crsr_t ib_crsr, /*!< in: cursor */ + ib_bool_t flag) /*!< in: true for increase */ +{ + const ib_cursor_t* cursor = (const ib_cursor_t*) ib_crsr; + row_prebuilt_t* prebuilt = cursor->prebuilt; + dict_table_t* table = prebuilt->table; + ib_err_t err = DB_SUCCESS; + + if (table != NULL) { + /* If memcached_sync_count is -1, means table is + doing DDL, we just return error. */ + if (table->memcached_sync_count == DICT_TABLE_IN_DDL) { + return(DB_ERROR); + } + + if (flag) { +#ifdef HAVE_ATOMIC_BUILTINS + os_atomic_increment_lint(&table->memcached_sync_count, 1); +#else + dict_mutex_enter_for_mysql(); + ++table->memcached_sync_count; + dict_mutex_exit_for_mysql(); +#endif + } else { +#ifdef HAVE_ATOMIC_BUILTINS + os_atomic_decrement_lint(&table->memcached_sync_count, 1); +#else + dict_mutex_enter_for_mysql(); + --table->memcached_sync_count; + dict_mutex_exit_for_mysql(); +#endif + ut_a(table->memcached_sync_count >= 0); + } + } else { + err = DB_TABLE_NOT_FOUND; + } + + return(err); +} diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 7e1483cfe85..e39d82a6c8b 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -2088,8 +2088,7 @@ btr_cur_optimistic_update( contain trx id and roll ptr fields */ ulint cmpl_info,/*!< in: compiler info on secondary index updates */ - que_thr_t* thr, /*!< in: query thread, or NULL if - appropriate flags are set */ + que_thr_t* thr, /*!< in: query thread */ trx_id_t trx_id, /*!< in: transaction id */ mtr_t* mtr) /*!< in/out: mini-transaction; if this is a secondary index, the caller must @@ -2382,8 +2381,7 @@ btr_cur_pessimistic_update( the values in update vector have no effect */ ulint cmpl_info,/*!< in: compiler info on secondary index updates */ - que_thr_t* thr, /*!< in: query thread, or NULL if - appropriate flags are set */ + que_thr_t* thr, /*!< in: query thread */ trx_id_t trx_id, /*!< in: transaction id */ mtr_t* mtr) /*!< in/out: mini-transaction; must be committed before latching any further pages */ diff --git a/storage/innobase/buf/buf0buddy.cc b/storage/innobase/buf/buf0buddy.cc index ee400fcdf23..fcf45b7fa1a 100644 --- a/storage/innobase/buf/buf0buddy.cc +++ b/storage/innobase/buf/buf0buddy.cc @@ -533,7 +533,6 @@ buf_buddy_relocate( { buf_page_t* bpage; const ulint size = BUF_BUDDY_LOW << i; - ib_mutex_t* mutex; ulint space; ulint offset; @@ -556,7 +555,12 @@ buf_buddy_relocate( ut_ad(space != BUF_BUDDY_STAMP_FREE); - bpage = buf_page_hash_get(buf_pool, space, offset); + ulint fold = buf_page_address_fold(space, offset); + rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold); + + rw_lock_x_lock(hash_lock); + + bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); if (!bpage || bpage->zip.data != src) { /* The block has probably been freshly @@ -564,6 +568,8 @@ buf_buddy_relocate( added to buf_pool->page_hash yet. Obviously, it cannot be relocated. */ + rw_lock_x_unlock(hash_lock); + return(false); } @@ -573,6 +579,8 @@ buf_buddy_relocate( For the sake of simplicity, give up. */ ut_ad(page_zip_get_size(&bpage->zip) < size); + rw_lock_x_unlock(hash_lock); + return(false); } @@ -580,27 +588,42 @@ buf_buddy_relocate( contain uninitialized data. */ UNIV_MEM_ASSERT_W(src, size); - mutex = buf_page_get_mutex(bpage); + ib_mutex_t* block_mutex = buf_page_get_mutex(bpage); - mutex_enter(mutex); + mutex_enter(block_mutex); if (buf_page_can_relocate(bpage)) { /* Relocate the compressed page. */ - ullint usec = ut_time_us(NULL); + ullint usec = ut_time_us(NULL); + ut_a(bpage->zip.data == src); - memcpy(dst, src, size); - bpage->zip.data = (page_zip_t*) dst; - mutex_exit(mutex); + + /* Note: This is potentially expensive, we need a better + solution here. We go with correctness for now. */ + ::memcpy(dst, src, size); + + bpage->zip.data = reinterpret_cast(dst); + + rw_lock_x_unlock(hash_lock); + + mutex_exit(block_mutex); + buf_buddy_mem_invalid( reinterpret_cast(src), i); buf_buddy_stat_t* buddy_stat = &buf_pool->buddy_stat[i]; - buddy_stat->relocated++; + + ++buddy_stat->relocated; + buddy_stat->relocated_usec += ut_time_us(NULL) - usec; + return(true); } - mutex_exit(mutex); + rw_lock_x_unlock(hash_lock); + + mutex_exit(block_mutex); + return(false); } diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index a8e833b5fa3..697b3f203b3 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -548,8 +548,11 @@ buf_page_is_corrupted( if (checksum_field1 == 0 && checksum_field2 == 0 && mach_read_from_4(read_buf + FIL_PAGE_LSN) == 0) { /* make sure that the page is really empty */ - ut_d(for (ulint i = 0; i < UNIV_PAGE_SIZE; i++) { - ut_a(read_buf[i] == 0); }); + for (ulint i = 0; i < UNIV_PAGE_SIZE; i++) { + if (read_buf[i] != 0) { + return(TRUE); + } + } return(FALSE); } @@ -1601,14 +1604,19 @@ buf_pool_watch_set( bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); - if (UNIV_LIKELY_NULL(bpage)) { + if (bpage != NULL) { page_found: if (!buf_pool_watch_is_sentinel(buf_pool, bpage)) { /* The page was loaded meanwhile. */ return(bpage); } + /* Add to an existing watch. */ - bpage->buf_fix_count++; +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_increment_uint32(&bpage->buf_fix_count, 1); +#else + ++bpage->buf_fix_count; +#endif /* PAGE_ATOMIC_REF_COUNT */ return(NULL); } @@ -1736,8 +1744,7 @@ buf_pool_watch_unset( buf_page_t* bpage; buf_pool_t* buf_pool = buf_pool_get(space, offset); ulint fold = buf_page_address_fold(space, offset); - rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, - fold); + rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold); /* We only need to have buf_pool mutex in case where we end up calling buf_pool_watch_remove but to obey latching order @@ -1748,22 +1755,24 @@ buf_pool_watch_unset( rw_lock_x_lock(hash_lock); + /* The page must exist because buf_pool_watch_set() increments + buf_fix_count. */ + bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); - /* The page must exist because buf_pool_watch_set() - increments buf_fix_count. */ - ut_a(bpage); - if (UNIV_UNLIKELY(!buf_pool_watch_is_sentinel(buf_pool, bpage))) { - ib_mutex_t* mutex = buf_page_get_mutex(bpage); - - mutex_enter(mutex); - ut_a(bpage->buf_fix_count > 0); - bpage->buf_fix_count--; - mutex_exit(mutex); + if (!buf_pool_watch_is_sentinel(buf_pool, bpage)) { + buf_block_unfix(reinterpret_cast(bpage)); } else { - ut_a(bpage->buf_fix_count > 0); - if (UNIV_LIKELY(!--bpage->buf_fix_count)) { + ut_ad(bpage->buf_fix_count > 0); + +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_decrement_uint32(&bpage->buf_fix_count, 1); +#else + --bpage->buf_fix_count; +#endif /* PAGE_ATOMIC_REF_COUNT */ + + if (bpage->buf_fix_count == 0) { buf_pool_watch_remove(buf_pool, fold, bpage); } } @@ -1793,10 +1802,10 @@ buf_pool_watch_occurred( rw_lock_s_lock(hash_lock); - bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); /* The page must exist because buf_pool_watch_set() increments buf_fix_count. */ - ut_a(bpage); + bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); + ret = !buf_pool_watch_is_sentinel(buf_pool, bpage); rw_lock_s_unlock(hash_lock); @@ -2034,27 +2043,32 @@ err_exit: case BUF_BLOCK_READY_FOR_USE: case BUF_BLOCK_MEMORY: case BUF_BLOCK_REMOVE_HASH: - break; + ut_error; + case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_DIRTY: block_mutex = &buf_pool->zip_mutex; mutex_enter(block_mutex); - bpage->buf_fix_count++; +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_increment_uint32(&bpage->buf_fix_count, 1); +#else + ++bpage->buf_fix_count; +#endif /* PAGE_ATOMIC_REF_COUNT */ goto got_block; case BUF_BLOCK_FILE_PAGE: /* Discard the uncompressed page frame if possible. */ if (!discard_attempted) { rw_lock_s_unlock(hash_lock); - buf_block_try_discard_uncompressed(space, - offset); + buf_block_try_discard_uncompressed(space, offset); discard_attempted = TRUE; goto lookup; } block_mutex = &((buf_block_t*) bpage)->mutex; + mutex_enter(block_mutex); - buf_block_buf_fix_inc((buf_block_t*) bpage, - __FILE__, __LINE__); + + buf_block_buf_fix_inc((buf_block_t*) bpage, __FILE__, __LINE__); goto got_block; } @@ -2067,7 +2081,7 @@ got_block: rw_lock_s_unlock(hash_lock); #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG ut_a(!bpage->file_page_was_freed); -#endif +#endif /* defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG */ buf_page_set_accessed(bpage); @@ -2378,7 +2392,7 @@ buf_block_is_uncompressed( const buf_block_t* block) /*!< in: pointer to block, not dereferenced */ { - if (UNIV_UNLIKELY((((ulint) block) % sizeof *block) != 0)) { + if ((((ulint) block) % sizeof *block) != 0) { /* The pointer should be aligned. */ return(FALSE); } @@ -2408,6 +2422,47 @@ buf_debug_execute_is_force_flush() } #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ +/** +Wait for the block to be read in. +@param block The block to check */ +static +void +buf_wait_for_read(buf_block_t* block) +{ + /* Note: For the PAGE_ATOMIC_REF_COUNT case: + + We are using the block->lock to check for IO state (and a dirty read). + We set the IO_READ state under the protection of the hash_lock + (and block->mutex). This is safe because another thread can only + access the block (and check for IO state) after the block has been + added to the page hashtable. */ + + if (buf_block_get_io_fix(block) == BUF_IO_READ) { + + /* Wait until the read operation completes */ + + ib_mutex_t* mutex = buf_page_get_mutex(&block->page); + + for (;;) { + buf_io_fix io_fix; + + mutex_enter(mutex); + + io_fix = buf_block_get_io_fix(block); + + mutex_exit(mutex); + + if (io_fix == BUF_IO_READ) { + /* Wait by temporaly s-latch */ + rw_lock_s_lock(&block->lock); + rw_lock_s_unlock(&block->lock); + } else { + break; + } + } + } +} + /********************************************************************//** This is the general function used to get access to a database page. @return pointer to the block or NULL */ @@ -2432,10 +2487,10 @@ buf_page_get_gen( ulint fold; unsigned access_time; ulint fix_type; - ibool must_read; rw_lock_t* hash_lock; - ib_mutex_t* block_mutex; ulint retries = 0; + buf_block_t* fix_block; + ib_mutex_t* fix_mutex = NULL; buf_pool_t* buf_pool = buf_pool_get(space, offset); ut_ad(mtr); @@ -2472,7 +2527,9 @@ loop: block = guess; rw_lock_s_lock(hash_lock); - if (block) { + + if (block != NULL) { + /* If the guess is a compressed page descriptor that has been allocated by buf_page_alloc_descriptor(), it may have been freed by buf_relocate(). */ @@ -2510,10 +2567,10 @@ loop: if (UNIV_LIKELY_NULL(block)) { /* We can release hash_lock after we - acquire block_mutex to make sure that - no state change takes place. */ - block_mutex = buf_page_get_mutex(&block->page); - mutex_enter(block_mutex); + increment the fix count to make + sure that no state change takes place. */ + fix_block = block; + buf_block_fix(fix_block); /* Now safe to release page_hash mutex */ rw_lock_x_unlock(hash_lock); @@ -2568,36 +2625,48 @@ loop: ut_a(++buf_dbg_counter % 5771 || buf_validate()); #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ goto loop; + } else { + fix_block = block; } - - /* We can release hash_lock after we acquire block_mutex to - make sure that no state change takes place. */ - block_mutex = buf_page_get_mutex(&block->page); - mutex_enter(block_mutex); + buf_block_fix(fix_block); /* Now safe to release page_hash mutex */ rw_lock_s_unlock(hash_lock); got_block: + + fix_mutex = buf_page_get_mutex(&fix_block->page); + ut_ad(page_zip_get_size(&block->page.zip) == zip_size); - ut_ad(mutex_own(block_mutex)); - must_read = buf_block_get_io_fix(block) == BUF_IO_READ; + if (mode == BUF_GET_IF_IN_POOL || mode == BUF_PEEK_IF_IN_POOL) { - if (must_read && (mode == BUF_GET_IF_IN_POOL - || mode == BUF_PEEK_IF_IN_POOL)) { + bool must_read; - /* The page is being read to buffer pool, - but we cannot wait around for the read to - complete. */ -null_exit: - mutex_exit(block_mutex); + { + buf_page_t* fix_page = &fix_block->page; - return(NULL); + mutex_enter(fix_mutex); + + buf_io_fix io_fix = buf_page_get_io_fix(fix_page); + + must_read = (io_fix == BUF_IO_READ); + + mutex_exit(fix_mutex); + } + + if (must_read) { + /* The page is being read to buffer pool, + but we cannot wait around for the read to + complete. */ + buf_block_unfix(fix_block); + + return(NULL); + } } - switch (buf_block_get_state(block)) { + switch(buf_block_get_state(fix_block)) { buf_page_t* bpage; case BUF_BLOCK_FILE_PAGE: @@ -2610,18 +2679,22 @@ null_exit: adaptive hash index. There cannot be an adaptive hash index for a compressed-only page, so do not bother decompressing the page. */ - goto null_exit; + buf_block_unfix(fix_block); + + return(NULL); } bpage = &block->page; - if (bpage->buf_fix_count + /* Note: We have already buffer fixed this block. */ + if (bpage->buf_fix_count > 1 || buf_page_get_io_fix(bpage) != BUF_IO_NONE) { + /* This condition often occurs when the buffer is not buffer-fixed, but I/O-fixed by buf_page_init_for_read(). */ - mutex_exit(block_mutex); -wait_until_unfixed: + buf_block_unfix(fix_block); + /* The block is buffer-fixed or I/O-fixed. Try again later. */ os_thread_sleep(WAIT_FOR_READ); @@ -2632,24 +2705,32 @@ wait_until_unfixed: /* Buffer-fix the block so that it cannot be evicted or relocated while we are attempting to allocate an uncompressed page. */ - bpage->buf_fix_count++; - /* Allocate an uncompressed page. */ - mutex_exit(block_mutex); block = buf_LRU_get_free_block(buf_pool); - ut_a(block); buf_pool_mutex_enter(buf_pool); rw_lock_x_lock(hash_lock); + /* Buffer-fixing prevents the page_hash from changing. */ ut_ad(bpage == buf_page_hash_get_low( buf_pool, space, offset, fold)); - mutex_enter(&block->mutex); + buf_block_mutex_enter(block); + mutex_enter(&buf_pool->zip_mutex); - if (--bpage->buf_fix_count + ut_ad(fix_block->page.buf_fix_count > 0); + +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_decrement_uint32(&fix_block->page.buf_fix_count, 1); +#else + --fix_block->page.buf_fix_count; +#endif /* PAGE_ATOMIC_REF_COUNT */ + + fix_block = block; + + if (bpage->buf_fix_count > 0 || buf_page_get_io_fix(bpage) != BUF_IO_NONE) { mutex_exit(&buf_pool->zip_mutex); @@ -2662,23 +2743,31 @@ wait_until_unfixed: buf_LRU_block_free_non_file_page(block); buf_pool_mutex_exit(buf_pool); rw_lock_x_unlock(hash_lock); - mutex_exit(&block->mutex); + buf_block_mutex_exit(block); - goto wait_until_unfixed; + /* Try again */ + goto loop; } /* Move the compressed page from bpage to block, and uncompress it. */ + /* Note: this is the uncompressed block and it is not + accessible by other threads yet because it is not in + any list or hash table */ buf_relocate(bpage, &block->page); + buf_block_init_low(block); + + /* Set after relocate(). */ + block->page.buf_fix_count = 1; + block->lock_hash_val = lock_rec_hash(space, offset); UNIV_MEM_DESC(&block->page.zip.data, - page_zip_get_size(&block->page.zip)); + page_zip_get_size(&block->page.zip)); - if (buf_page_get_state(&block->page) - == BUF_BLOCK_ZIP_PAGE) { + if (buf_page_get_state(&block->page) == BUF_BLOCK_ZIP_PAGE) { #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG UT_LIST_REMOVE(list, buf_pool->zip_clean, &block->page); @@ -2686,8 +2775,7 @@ wait_until_unfixed: ut_ad(!block->page.in_flush_list); } else { /* Relocate buf_pool->flush_list. */ - buf_flush_relocate_on_flush_list(bpage, - &block->page); + buf_flush_relocate_on_flush_list(bpage, &block->page); } /* Buffer-fix, I/O-fix, and X-latch the block @@ -2698,7 +2786,6 @@ wait_until_unfixed: /* Insert at the front of unzip_LRU list */ buf_unzip_LRU_add_block(block, FALSE); - block->page.buf_fix_count = 1; buf_block_set_io_fix(block, BUF_IO_READ); rw_lock_x_lock_inline(&block->lock, 0, file, line); @@ -2706,11 +2793,14 @@ wait_until_unfixed: rw_lock_x_unlock(hash_lock); - buf_pool->n_pend_unzip++; + ++buf_pool->n_pend_unzip; + buf_pool_mutex_exit(buf_pool); access_time = buf_page_is_accessed(&block->page); - mutex_exit(&block->mutex); + + buf_block_mutex_exit(block); + mutex_exit(&buf_pool->zip_mutex); buf_page_free_descriptor(bpage); @@ -2721,9 +2811,12 @@ wait_until_unfixed: /* Page checksum verification is already done when the page is read from disk. Hence page checksum verification is not necessary when decompressing the page. */ - ut_a(buf_zip_decompress(block, FALSE)); + { + bool success = buf_zip_decompress(block, FALSE); + ut_a(success); + } - if (UNIV_LIKELY(!recv_no_ibuf_operations)) { + if (!recv_no_ibuf_operations) { if (access_time) { #ifdef UNIV_IBUF_COUNT_DEBUG ut_a(ibuf_count_get(space, offset) == 0); @@ -2734,13 +2827,19 @@ wait_until_unfixed: } } - /* Unfix and unlatch the block. */ buf_pool_mutex_enter(buf_pool); - mutex_enter(&block->mutex); - block->page.buf_fix_count--; - buf_block_set_io_fix(block, BUF_IO_NONE); - buf_pool->n_pend_unzip--; + + /* Unfix and unlatch the block. */ + buf_block_mutex_enter(fix_block); + + buf_block_set_io_fix(fix_block, BUF_IO_NONE); + + buf_block_mutex_exit(fix_block); + + --buf_pool->n_pend_unzip; + buf_pool_mutex_exit(buf_pool); + rw_lock_x_unlock(&block->lock); break; @@ -2754,43 +2853,40 @@ wait_until_unfixed: break; } + ut_ad(block == fix_block); + ut_ad(fix_block->page.buf_fix_count > 0); + #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX)); ut_ad(!rw_lock_own(hash_lock, RW_LOCK_SHARED)); #endif /* UNIV_SYNC_DEBUG */ - ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); + ut_ad(buf_block_get_state(fix_block) == BUF_BLOCK_FILE_PAGE); #if UNIV_WORD_SIZE == 4 /* On 32-bit systems, there is no padding in buf_page_t. On other systems, Valgrind could complain about uninitialized pad bytes. */ - UNIV_MEM_ASSERT_RW(&block->page, sizeof block->page); + UNIV_MEM_ASSERT_RW(&fix_block->page, sizeof(fix_block->page)); #endif #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG if ((mode == BUF_GET_IF_IN_POOL || mode == BUF_GET_IF_IN_POOL_OR_WATCH) && (ibuf_debug || buf_debug_execute_is_force_flush())) { + /* Try to evict the block from the buffer pool, to use the insert buffer (change buffer) as much as possible. */ - /* To obey the latching order, release the - block->mutex before acquiring buf_pool->mutex. Protect - the block from changes by temporarily buffer-fixing it - for the time we are not holding block->mutex. */ - buf_block_buf_fix_inc(block, file, line); - mutex_exit(&block->mutex); buf_pool_mutex_enter(buf_pool); - mutex_enter(&block->mutex); - buf_block_buf_fix_dec(block); - mutex_exit(&block->mutex); + + buf_block_unfix(fix_block); /* Now we are only holding the buf_pool->mutex, not block->mutex or hash_lock. Blocks cannot be relocated or enter or exit the buf_pool while we are holding the buf_pool->mutex. */ - if (buf_LRU_free_page(&block->page, true)) { + if (buf_LRU_free_page(&fix_block->page, true)) { buf_pool_mutex_exit(buf_pool); rw_lock_x_lock(hash_lock); @@ -2807,7 +2903,7 @@ wait_until_unfixed: rw_lock_x_unlock(hash_lock); - if (UNIV_LIKELY_NULL(block)) { + if (block != NULL) { /* Either the page has been read in or a watch was set on that in the window where we released the buf_pool::mutex @@ -2823,103 +2919,114 @@ wait_until_unfixed: return(NULL); } - mutex_enter(&block->mutex); + mutex_enter(&fix_block->mutex); - if (buf_flush_page_try(buf_pool, block)) { + if (buf_flush_page_try(buf_pool, fix_block)) { fprintf(stderr, "innodb_change_buffering_debug flush %u %u\n", (unsigned) space, (unsigned) offset); - guess = block; + guess = fix_block; goto loop; } + buf_block_mutex_exit(fix_block); + + buf_block_fix(fix_block); + /* Failed to evict the page; change it directly */ buf_pool_mutex_exit(buf_pool); } #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ - buf_block_buf_fix_inc(block, file, line); + ut_ad(fix_block->page.buf_fix_count > 0); + +#ifdef UNIV_SYNC_DEBUG + /* We have already buffer fixed the page, and we are committed to + returning this page to the caller. Register for debugging. */ + { + ibool ret; + ret = rw_lock_s_lock_nowait(&fix_block->debug_latch, file, line); + ut_a(ret); + } +#endif /* UNIV_SYNC_DEBUG */ + #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG ut_a(mode == BUF_GET_POSSIBLY_FREED - || !block->page.file_page_was_freed); + || !fix_block->page.file_page_was_freed); #endif /* Check if this is the first access to the page */ - access_time = buf_page_is_accessed(&block->page); + access_time = buf_page_is_accessed(&fix_block->page); - buf_page_set_accessed(&block->page); + /* This is a heuristic and we don't care about ordering issues. */ + if (access_time == 0) { + buf_block_mutex_enter(fix_block); - mutex_exit(&block->mutex); + buf_page_set_accessed(&fix_block->page); + + buf_block_mutex_exit(fix_block); + } if (mode != BUF_PEEK_IF_IN_POOL) { - buf_page_make_young_if_needed(&block->page); + buf_page_make_young_if_needed(&fix_block->page); } #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG ut_a(++buf_dbg_counter % 5771 || buf_validate()); - ut_a(block->page.buf_fix_count > 0); - ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); + ut_a(fix_block->page.buf_fix_count > 0); + ut_a(buf_block_get_state(fix_block) == BUF_BLOCK_FILE_PAGE); #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ +#ifdef PAGE_ATOMIC_REF_COUNT + /* We have to wait here because the IO_READ state was set + under the protection of the hash_lock and the block->mutex + but not the block->lock. */ + buf_wait_for_read(fix_block); +#endif /* PAGE_ATOMIC_REF_COUNT */ + switch (rw_latch) { case RW_NO_LATCH: - if (must_read) { - /* Let us wait until the read operation - completes */ - for (;;) { - enum buf_io_fix io_fix; - - mutex_enter(&block->mutex); - io_fix = buf_block_get_io_fix(block); - mutex_exit(&block->mutex); - - if (io_fix == BUF_IO_READ) { - /* wait by temporaly s-latch */ - rw_lock_s_lock(&(block->lock)); - rw_lock_s_unlock(&(block->lock)); - } else { - break; - } - } - } +#ifndef PAGE_ATOMIC_REF_COUNT + buf_wait_for_read(fix_block); +#endif /* !PAGE_ATOMIC_REF_COUNT */ fix_type = MTR_MEMO_BUF_FIX; break; case RW_S_LATCH: - rw_lock_s_lock_inline(&(block->lock), 0, file, line); + rw_lock_s_lock_inline(&fix_block->lock, 0, file, line); fix_type = MTR_MEMO_PAGE_S_FIX; break; default: ut_ad(rw_latch == RW_X_LATCH); - rw_lock_x_lock_inline(&(block->lock), 0, file, line); + rw_lock_x_lock_inline(&fix_block->lock, 0, file, line); fix_type = MTR_MEMO_PAGE_X_FIX; break; } - mtr_memo_push(mtr, block, fix_type); + mtr_memo_push(mtr, fix_block, fix_type); if (mode != BUF_PEEK_IF_IN_POOL && !access_time) { /* In the case of a first access, try to apply linear read-ahead */ - buf_read_ahead_linear(space, zip_size, offset, - ibuf_inside(mtr)); + buf_read_ahead_linear( + space, zip_size, offset, ibuf_inside(mtr)); } #ifdef UNIV_IBUF_COUNT_DEBUG - ut_a(ibuf_count_get(buf_block_get_space(block), - buf_block_get_page_no(block)) == 0); + ut_a(ibuf_count_get(buf_block_get_space(fix_block), + buf_block_get_page_no(fix_block)) == 0); #endif #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX)); ut_ad(!rw_lock_own(hash_lock, RW_LOCK_SHARED)); #endif /* UNIV_SYNC_DEBUG */ - return(block); + return(fix_block); } /********************************************************************//** @@ -2982,9 +3089,7 @@ buf_page_optimistic_get( } if (UNIV_UNLIKELY(!success)) { - mutex_enter(&block->mutex); buf_block_buf_fix_dec(block); - mutex_exit(&block->mutex); return(FALSE); } @@ -2998,9 +3103,7 @@ buf_page_optimistic_get( rw_lock_x_unlock(&(block->lock)); } - mutex_enter(&block->mutex); buf_block_buf_fix_dec(block); - mutex_exit(&block->mutex); return(FALSE); } @@ -3105,9 +3208,7 @@ buf_page_get_known_nowait( } if (!success) { - mutex_enter(&block->mutex); buf_block_buf_fix_dec(block); - mutex_exit(&block->mutex); return(FALSE); } @@ -3206,9 +3307,7 @@ buf_page_try_get_func( } if (!success) { - mutex_enter(&block->mutex); buf_block_buf_fix_dec(block); - mutex_exit(&block->mutex); return(NULL); } @@ -3306,13 +3405,20 @@ buf_page_init( hash_page = buf_page_hash_get_low(buf_pool, space, offset, fold); - if (UNIV_LIKELY(!hash_page)) { + if (hash_page == NULL) { + /* Block not found in the hash table */ } else if (buf_pool_watch_is_sentinel(buf_pool, hash_page)) { - /* Preserve the reference count. */ - ulint buf_fix_count = hash_page->buf_fix_count; + ib_uint32_t buf_fix_count = hash_page->buf_fix_count; + + ut_a(buf_fix_count > 0); + +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_increment_uint32( + &block->page.buf_fix_count, buf_fix_count); +#else + block->page.buf_fix_count += ulint(buf_fix_count); +#endif /* PAGE_ATOMIC_REF_COUNT */ - ut_a(buf_fix_count > 0); - block->page.buf_fix_count += buf_fix_count; buf_pool_watch_remove(buf_pool, fold, hash_page); } else { fprintf(stderr, @@ -3335,8 +3441,9 @@ buf_page_init( ut_ad(!block->page.in_zip_hash); ut_ad(!block->page.in_page_hash); ut_d(block->page.in_page_hash = TRUE); - HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, - fold, &block->page); + + HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold, &block->page); + if (zip_size) { page_zip_set_size(&block->page.zip, zip_size); } @@ -3446,6 +3553,15 @@ err_exit: ut_ad(buf_pool_from_bpage(bpage) == buf_pool); buf_page_init(buf_pool, space, offset, fold, zip_size, block); + +#ifdef PAGE_ATOMIC_REF_COUNT + /* Note: We set the io state without the protection of + the block->lock. This is because other threads cannot + access this block unless it is in the hash table. */ + + buf_page_set_io_fix(bpage, BUF_IO_READ); +#endif /* PAGE_ATOMIC_REF_COUNT */ + rw_lock_x_unlock(hash_lock); /* The block must be put to the LRU list, to the old blocks */ @@ -3461,7 +3577,10 @@ err_exit: io-handler thread. */ rw_lock_x_lock_gen(&block->lock, BUF_IO_READ); + +#ifndef PAGE_ATOMIC_REF_COUNT buf_page_set_io_fix(bpage, BUF_IO_READ); +#endif /* !PAGE_ATOMIC_REF_COUNT */ if (zip_size) { /* buf_pool->mutex may be released and @@ -3549,12 +3668,22 @@ err_exit: ut_d(bpage->in_page_hash = TRUE); - if (UNIV_LIKELY_NULL(watch_page)) { + if (watch_page != NULL) { /* Preserve the reference count. */ - ulint buf_fix_count = watch_page->buf_fix_count; + ib_uint32_t buf_fix_count; + + buf_fix_count = watch_page->buf_fix_count; + ut_a(buf_fix_count > 0); + +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_increment_uint32( + &bpage->buf_fix_count, buf_fix_count); +#else bpage->buf_fix_count += buf_fix_count; +#endif /* PAGE_ATOMIC_REF_COUNT */ + ut_ad(buf_pool_watch_is_sentinel(buf_pool, watch_page)); buf_pool_watch_remove(buf_pool, fold, watch_page); } @@ -3649,8 +3778,7 @@ buf_page_create( buf_block_free(free_block); - return(buf_page_get_with_no_latch(space, zip_size, - offset, mtr)); + return(buf_page_get_with_no_latch(space, zip_size, offset, mtr)); } /* If we get here, the page was not in buf_pool: init it there */ diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index 2b2483fde6d..e1018c89e9b 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -351,13 +351,12 @@ At a database startup initializes the doublewrite buffer memory structure if we already have a doublewrite buffer created in the data files. If we are upgrading to an InnoDB version which supports multiple tablespaces, then this function performs the necessary update operations. If we are in a crash -recovery, this function uses a possible doublewrite buffer to restore -half-written pages in the data files. */ +recovery, this function loads the pages from double write buffer into memory. */ UNIV_INTERN void -buf_dblwr_init_or_restore_pages( -/*============================*/ - ibool restore_corrupt_pages) /*!< in: TRUE=restore pages */ +buf_dblwr_init_or_load_pages( +/*==========================*/ + bool load_corrupt_pages) { byte* buf; byte* read_buf; @@ -368,8 +367,8 @@ buf_dblwr_init_or_restore_pages( ibool reset_space_ids = FALSE; byte* doublewrite; ulint space_id; - ulint page_no; ulint i; + recv_dblwr_t& recv_dblwr = recv_sys->dblwr; /* We do the file i/o past the buffer pool */ @@ -431,13 +430,12 @@ buf_dblwr_init_or_restore_pages( for (i = 0; i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * 2; i++) { ulint source_page_no; - page_no = mach_read_from_4(page + FIL_PAGE_OFFSET); if (reset_space_ids) { space_id = 0; mach_write_to_4(page - + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0); + + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id); /* We do not need to calculate new checksums for the pages because the field .._SPACE_ID does not affect them. Write the page back to where we read it from. */ @@ -449,19 +447,50 @@ buf_dblwr_init_or_restore_pages( + i - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE; } - fil_io(OS_FILE_WRITE, true, 0, 0, source_page_no, 0, + fil_io(OS_FILE_WRITE, true, space_id, 0, source_page_no, 0, UNIV_PAGE_SIZE, page, NULL); - } else { - space_id = mach_read_from_4( - page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + } else if (load_corrupt_pages) { + + recv_dblwr.add(page); } - if (!restore_corrupt_pages) { - /* The database was shut down gracefully: no need to - restore pages */ + page += UNIV_PAGE_SIZE; + } - } else if (!fil_tablespace_exists_in_mem(space_id)) { + fil_flush_file_spaces(FIL_TABLESPACE); + +leave_func: + ut_free(unaligned_read_buf); +} + +/****************************************************************//** +Process the double write buffer pages. */ +void +buf_dblwr_process() +/*===============*/ +{ + ulint space_id; + ulint page_no; + ulint page_no_dblwr = 0; + byte* page; + byte* read_buf; + byte* unaligned_read_buf; + recv_dblwr_t& recv_dblwr = recv_sys->dblwr; + + unaligned_read_buf = static_cast(ut_malloc(2 * UNIV_PAGE_SIZE)); + + read_buf = static_cast( + ut_align(unaligned_read_buf, UNIV_PAGE_SIZE)); + + for (std::list::iterator i = recv_dblwr.pages.begin(); + i != recv_dblwr.pages.end(); ++i, ++page_no_dblwr ) { + + page = *i; + page_no = mach_read_from_4(page + FIL_PAGE_OFFSET); + space_id = mach_read_from_4(page + FIL_PAGE_SPACE_ID); + + if (!fil_tablespace_exists_in_mem(space_id)) { /* Maybe we have dropped the single-table tablespace and this page once belonged to it: do nothing */ @@ -472,19 +501,8 @@ buf_dblwr_init_or_restore_pages( "within space bounds; space id %lu " "page number %lu, page %lu in " "doublewrite buf.", - (ulong) space_id, (ulong) page_no, (ulong) i); - - } else if (space_id == TRX_SYS_SPACE - && ((page_no >= block1 - && page_no - < block1 + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) - || (page_no >= block2 - && page_no - < (block2 - + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)))) { - - /* It is an unwritten doublewrite buffer page: - do nothing */ + (ulong) space_id, (ulong) page_no, + page_no_dblwr); } else { ulint zip_size = fil_space_get_zip_size(space_id); @@ -551,14 +569,11 @@ buf_dblwr_init_or_restore_pages( " the doublewrite buffer."); } } - - page += UNIV_PAGE_SIZE; } fil_flush_file_spaces(FIL_TABLESPACE); - -leave_func: ut_free(unaligned_read_buf); + recv_dblwr.pages.clear(); } /****************************************************************//** @@ -776,6 +791,7 @@ buf_dblwr_write_block_to_datafile( fil_io(flags, sync, buf_block_get_space(block), 0, buf_block_get_page_no(block), 0, UNIV_PAGE_SIZE, (void*) block->frame, (void*) block); + } /********************************************************************//** diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 3af434b77f4..0fa5c744e51 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -502,15 +502,15 @@ buf_flush_ready_for_replace( #ifdef UNIV_DEBUG buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); ut_ad(buf_pool_mutex_own(buf_pool)); -#endif +#endif /* UNIV_DEBUG */ ut_ad(mutex_own(buf_page_get_mutex(bpage))); ut_ad(bpage->in_LRU_list); - if (UNIV_LIKELY(buf_page_in_file(bpage))) { + if (buf_page_in_file(bpage)) { return(bpage->oldest_modification == 0 - && buf_page_get_io_fix(bpage) == BUF_IO_NONE - && bpage->buf_fix_count == 0); + && bpage->buf_fix_count == 0 + && buf_page_get_io_fix(bpage) == BUF_IO_NONE); } ut_print_timestamp(stderr); @@ -553,17 +553,10 @@ buf_flush_ready_for_flush( switch (flush_type) { case BUF_FLUSH_LIST: - return(true); - case BUF_FLUSH_LRU: case BUF_FLUSH_SINGLE_PAGE: - /* Because any thread may call single page flush, even - when owning locks on pages, to avoid deadlocks, we must - make sure that the that it is not buffer fixed. - The same holds true for LRU flush because a user thread - may end up waiting for an LRU flush to end while - holding locks on other pages. */ - return(bpage->buf_fix_count == 0); + return(true); + case BUF_FLUSH_N_TYPES: break; } @@ -991,9 +984,10 @@ NOTE: in simulated aio we must call os_aio_simulated_wake_handler_threads after we have posted a batch of writes! NOTE: buf_pool->mutex and buf_page_get_mutex(bpage) must be held upon entering this function, and they will be released by this -function. */ +function if it returns true. +@return TRUE if the page was flushed */ UNIV_INTERN -void +bool buf_flush_page( /*===========*/ buf_pool_t* buf_pool, /*!< in: buffer pool instance */ @@ -1001,109 +995,84 @@ buf_flush_page( buf_flush_t flush_type, /*!< in: type of flush */ bool sync) /*!< in: true if sync IO request */ { - ib_mutex_t* block_mutex; - ibool is_uncompressed; - ut_ad(flush_type < BUF_FLUSH_N_TYPES); ut_ad(buf_pool_mutex_own(buf_pool)); ut_ad(buf_page_in_file(bpage)); ut_ad(!sync || flush_type == BUF_FLUSH_SINGLE_PAGE); - block_mutex = buf_page_get_mutex(bpage); + ib_mutex_t* block_mutex = buf_page_get_mutex(bpage); + ut_ad(mutex_own(block_mutex)); ut_ad(buf_flush_ready_for_flush(bpage, flush_type)); - buf_page_set_io_fix(bpage, BUF_IO_WRITE); + bool is_uncompressed; - buf_page_set_flush_type(bpage, flush_type); + is_uncompressed = (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE); + ut_ad(is_uncompressed == (block_mutex != &buf_pool->zip_mutex)); - if (buf_pool->n_flush[flush_type] == 0) { + ibool flush; + rw_lock_t* rw_lock; + bool no_fix_count = bpage->buf_fix_count == 0; - os_event_reset(buf_pool->no_flush[flush_type]); + if (!is_uncompressed) { + flush = TRUE; + rw_lock = NULL; + + } else if (!(no_fix_count || flush_type == BUF_FLUSH_LIST)) { + /* This is a heuristic, to avoid expensive S attempts. */ + flush = FALSE; + } else { + + rw_lock = &reinterpret_cast(bpage)->lock; + + if (flush_type != BUF_FLUSH_LIST) { + flush = rw_lock_s_lock_gen_nowait( + rw_lock, BUF_IO_WRITE); + } else { + /* Will S lock later */ + flush = TRUE; + } } - buf_pool->n_flush[flush_type]++; + if (flush) { - is_uncompressed = (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE); - ut_ad(is_uncompressed == (block_mutex != &buf_pool->zip_mutex)); + /* We are committed to flushing by the time we get here */ - switch (flush_type) { - ibool is_s_latched; - case BUF_FLUSH_LIST: - /* If the simulated aio thread is not running, we must - not wait for any latch, as we may end up in a deadlock: - if buf_fix_count == 0, then we know we need not wait */ + buf_page_set_io_fix(bpage, BUF_IO_WRITE); - is_s_latched = (bpage->buf_fix_count == 0); - if (is_s_latched && is_uncompressed) { - rw_lock_s_lock_gen(&((buf_block_t*) bpage)->lock, - BUF_IO_WRITE); + buf_page_set_flush_type(bpage, flush_type); + + if (buf_pool->n_flush[flush_type] == 0) { + + os_event_reset(buf_pool->no_flush[flush_type]); } + ++buf_pool->n_flush[flush_type]; + mutex_exit(block_mutex); buf_pool_mutex_exit(buf_pool); - /* Even though bpage is not protected by any mutex at - this point, it is safe to access bpage, because it is - io_fixed and oldest_modification != 0. Thus, it - cannot be relocated in the buffer pool or removed from - flush_list or LRU_list. */ - - if (!is_s_latched) { + if (flush_type == BUF_FLUSH_LIST + && is_uncompressed + && !rw_lock_s_lock_gen_nowait(rw_lock, BUF_IO_WRITE)) { + /* avoiding deadlock possibility involves doublewrite + buffer, should flush it, because it might hold the + another block->lock. */ buf_dblwr_flush_buffered_writes(); - if (is_uncompressed) { - rw_lock_s_lock_gen(&((buf_block_t*) bpage) - ->lock, BUF_IO_WRITE); - } - } + rw_lock_s_lock_gen(rw_lock, BUF_IO_WRITE); + } - break; + /* Even though bpage is not protected by any mutex at this + point, it is safe to access bpage, because it is io_fixed and + oldest_modification != 0. Thus, it cannot be relocated in the + buffer pool or removed from flush_list or LRU_list. */ - case BUF_FLUSH_LRU: - case BUF_FLUSH_SINGLE_PAGE: - /* VERY IMPORTANT: - Because any thread may call single page flush, even when - owning locks on pages, to avoid deadlocks, we must make - sure that the s-lock is acquired on the page without - waiting: this is accomplished because - buf_flush_ready_for_flush() must hold, and that requires - the page not to be bufferfixed. - The same holds true for LRU flush because a user thread - may end up waiting for an LRU flush to end while - holding locks on other pages. */ + buf_flush_write_block_low(bpage, flush_type, sync); + } - if (is_uncompressed) { - rw_lock_s_lock_gen(&((buf_block_t*) bpage)->lock, - BUF_IO_WRITE); - } - - /* Note that the s-latch is acquired before releasing the - buf_pool mutex: this ensures that the latch is acquired - immediately. */ - - mutex_exit(block_mutex); - buf_pool_mutex_exit(buf_pool); - break; - - default: - ut_error; - } - - /* Even though bpage is not protected by any mutex at this - point, it is safe to access bpage, because it is io_fixed and - oldest_modification != 0. Thus, it cannot be relocated in the - buffer pool or removed from flush_list or LRU_list. */ - -#ifdef UNIV_DEBUG - if (buf_debug_prints) { - fprintf(stderr, - "Flushing %u space %u page %u\n", - flush_type, bpage->space, bpage->offset); - } -#endif /* UNIV_DEBUG */ - buf_flush_write_block_low(bpage, flush_type, sync); + return(flush); } # if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG @@ -1130,8 +1099,8 @@ buf_flush_page_try( /* The following call will release the buffer pool and block mutex. */ - buf_flush_page(buf_pool, &block->page, BUF_FLUSH_SINGLE_PAGE, true); - return(TRUE); + return(buf_flush_page( + buf_pool, &block->page, BUF_FLUSH_SINGLE_PAGE, true)); } # endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ /***********************************************************//** @@ -1203,7 +1172,6 @@ buf_flush_try_neighbors( ulint i; ulint low; ulint high; - ulint count = 0; buf_pool_t* buf_pool = buf_pool_get(space, offset); ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST); @@ -1259,9 +1227,9 @@ buf_flush_try_neighbors( high = fil_space_get_size(space); } - for (i = low; i < high; i++) { + ulint count = 0; - buf_page_t* bpage; + for (i = low; i < high; i++) { if ((count + n_flushed) >= n_to_flush) { @@ -1283,9 +1251,9 @@ buf_flush_try_neighbors( buf_pool_mutex_enter(buf_pool); /* We only want to flush pages from this buffer pool. */ - bpage = buf_page_hash_get(buf_pool, space, i); + buf_page_t* bpage = buf_page_hash_get(buf_pool, space, i); - if (!bpage) { + if (bpage == NULL) { buf_pool_mutex_exit(buf_pool); continue; @@ -1299,30 +1267,24 @@ buf_flush_try_neighbors( if (flush_type != BUF_FLUSH_LRU || i == offset || buf_page_is_old(bpage)) { + ib_mutex_t* block_mutex = buf_page_get_mutex(bpage); mutex_enter(block_mutex); if (buf_flush_ready_for_flush(bpage, flush_type) - && (i == offset || !bpage->buf_fix_count)) { - /* We only try to flush those - neighbors != offset where the buf fix - count is zero, as we then know that we - probably can latch the page without a - semaphore wait. Semaphore waits are - expensive because we must flush the - doublewrite buffer before we start - waiting. */ + && (i == offset || bpage->buf_fix_count == 0) + && buf_flush_page( + buf_pool, bpage, flush_type, false)) { + + ++count; - buf_flush_page(buf_pool, bpage, flush_type, false); - ut_ad(!mutex_own(block_mutex)); - ut_ad(!buf_pool_mutex_own(buf_pool)); - count++; continue; - } else { - mutex_exit(block_mutex); } + + mutex_exit(block_mutex); } + buf_pool_mutex_exit(buf_pool); } @@ -1358,8 +1320,8 @@ buf_flush_page_and_try_neighbors( ulint* count) /*!< in/out: number of pages flushed */ { + ibool flushed; ib_mutex_t* block_mutex; - ibool flushed = FALSE; #ifdef UNIV_DEBUG buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); #endif /* UNIV_DEBUG */ @@ -1372,8 +1334,6 @@ buf_flush_page_and_try_neighbors( ut_a(buf_page_in_file(bpage)); if (buf_flush_ready_for_flush(bpage, flush_type)) { - ulint space; - ulint offset; buf_pool_t* buf_pool; buf_pool = buf_pool_from_bpage(bpage); @@ -1382,22 +1342,22 @@ buf_flush_page_and_try_neighbors( /* These fields are protected by both the buffer pool mutex and block mutex. */ - space = buf_page_get_space(bpage); - offset = buf_page_get_page_no(bpage); + ulint space = buf_page_get_space(bpage); + ulint offset = buf_page_get_page_no(bpage); mutex_exit(block_mutex); /* Try to flush also all the neighbors */ - *count += buf_flush_try_neighbors(space, - offset, - flush_type, - *count, - n_to_flush); + *count += buf_flush_try_neighbors( + space, offset, flush_type, *count, n_to_flush); buf_pool_mutex_enter(buf_pool); + flushed = TRUE; + } else { mutex_exit(block_mutex); + flushed = FALSE; } ut_ad(buf_pool_mutex_own(buf_pool)); @@ -1480,8 +1440,8 @@ buf_flush_LRU_list_batch( blocks in the free_list */ { buf_page_t* bpage; - ulint scanned = 0; ulint count = 0; + ulint scanned = 0; ulint free_len = UT_LIST_GET_LEN(buf_pool->free); ulint lru_len = UT_LIST_GET_LEN(buf_pool->LRU); @@ -1520,15 +1480,44 @@ buf_flush_LRU_list_batch( } else { bpage = UT_LIST_GET_PREV(LRU, bpage); } - } else if (buf_flush_page_and_try_neighbors( - bpage, - BUF_FLUSH_LRU, max, &count)) { - - /* buf_pool->mutex was released. - Restart the scan. */ - bpage = UT_LIST_GET_LAST(buf_pool->LRU); } else { - bpage = UT_LIST_GET_PREV(LRU, bpage); + ulint space; + ulint offset; + buf_page_t* prev_bpage; + + prev_bpage = UT_LIST_GET_PREV(LRU, bpage); + + /* Save the previous bpage */ + + if (prev_bpage != NULL) { + space = prev_bpage->space; + offset = prev_bpage->offset; + } else { + space = ULINT_UNDEFINED; + offset = ULINT_UNDEFINED; + } + + if (!buf_flush_page_and_try_neighbors( + bpage, BUF_FLUSH_LRU, max, &count)) { + + bpage = prev_bpage; + } else { + /* buf_pool->mutex was released. + reposition the iterator. Note: the + prev block could have been repositioned + too but that should be rare. */ + + if (prev_bpage != NULL) { + + ut_ad(space != ULINT_UNDEFINED); + ut_ad(offset != ULINT_UNDEFINED); + + prev_bpage = buf_page_hash_get( + buf_pool, space, offset); + } + + bpage = prev_bpage; + } } free_len = UT_LIST_GET_LEN(buf_pool->free); @@ -1836,7 +1825,7 @@ buf_flush_wait_batch_end( } } else { thd_wait_begin(NULL, THD_WAIT_DISKIO); - os_event_wait(buf_pool->no_flush[type]); + os_event_wait(buf_pool->no_flush[type]); thd_wait_end(NULL); } } @@ -1985,9 +1974,6 @@ buf_flush_single_page_from_LRU( { ulint scanned; buf_page_t* bpage; - ib_mutex_t* block_mutex; - ibool freed; - bool evict_zip; buf_pool_mutex_enter(buf_pool); @@ -1995,14 +1981,25 @@ buf_flush_single_page_from_LRU( bpage != NULL; bpage = UT_LIST_GET_PREV(LRU, bpage), ++scanned) { - block_mutex = buf_page_get_mutex(bpage); + ib_mutex_t* block_mutex = buf_page_get_mutex(bpage); + mutex_enter(block_mutex); - if (buf_flush_ready_for_flush(bpage, - BUF_FLUSH_SINGLE_PAGE)) { - /* buf_flush_page() will release the block - mutex */ - break; + + if (buf_flush_ready_for_flush(bpage, BUF_FLUSH_SINGLE_PAGE)) { + + /* The following call will release the buffer pool + and block mutex. */ + + ibool flushed = buf_flush_page( + buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE, true); + + if (flushed) { + /* buf_flush_page() will release the + block mutex */ + break; + } } + mutex_exit(block_mutex); } @@ -2012,15 +2009,14 @@ buf_flush_single_page_from_LRU( MONITOR_LRU_SINGLE_FLUSH_SCANNED_PER_CALL, scanned); - if (!bpage) { + if (bpage == NULL) { /* Can't find a single flushable page. */ buf_pool_mutex_exit(buf_pool); return(FALSE); } - /* The following call will release the buffer pool and - block mutex. */ - buf_flush_page(buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE, true); + + ibool freed = FALSE; /* At this point the page has been written to the disk. As we are not holding buffer pool or block mutex therefore @@ -2035,27 +2031,25 @@ buf_flush_single_page_from_LRU( bpage != NULL; bpage = UT_LIST_GET_PREV(LRU, bpage)) { - ibool ready; + ib_mutex_t* block_mutex = buf_page_get_mutex(bpage); - block_mutex = buf_page_get_mutex(bpage); mutex_enter(block_mutex); - ready = buf_flush_ready_for_replace(bpage); + + ibool ready = buf_flush_ready_for_replace(bpage); + mutex_exit(block_mutex); + if (ready) { + bool evict_zip; + + evict_zip = !buf_LRU_evict_from_unzip_LRU(buf_pool);; + + freed = buf_LRU_free_page(bpage, evict_zip); + break; } - } - if (!bpage) { - /* Can't find a single replaceable page. */ - buf_pool_mutex_exit(buf_pool); - return(FALSE); - } - - evict_zip = !buf_LRU_evict_from_unzip_LRU(buf_pool);; - - freed = buf_LRU_free_page(bpage, evict_zip); buf_pool_mutex_exit(buf_pool); return(freed); diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index bc73119c227..98d0ec2d2ec 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -473,12 +473,8 @@ buf_flush_or_remove_page( yet; maybe the system is currently reading it in, or flushing the modifications to the file */ return(false); - } - ib_mutex_t* block_mutex = buf_page_get_mutex(bpage); - bool processed = false; - /* We have to release the flush_list_mutex to obey the latching order. We are however guaranteed that the page will stay in the flush_list and won't be relocated because @@ -487,6 +483,9 @@ buf_flush_or_remove_page( buf_flush_list_mutex_exit(buf_pool); + bool processed; + ib_mutex_t* block_mutex = buf_page_get_mutex(bpage); + mutex_enter(block_mutex); ut_ad(bpage->oldest_modification != 0); @@ -494,18 +493,11 @@ buf_flush_or_remove_page( if (!flush) { buf_flush_remove(bpage); - - mutex_exit(block_mutex); - processed = true; - } else if (buf_flush_ready_for_flush(bpage, - BUF_FLUSH_SINGLE_PAGE)) { - - /* The following call will release the buffer pool - and block mutex. */ - buf_flush_page(buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE, false); - ut_ad(!mutex_own(block_mutex)); + } else if (buf_flush_ready_for_flush(bpage, BUF_FLUSH_SINGLE_PAGE) + && buf_flush_page( + buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE, false)) { /* Wake possible simulated aio thread to actually post the writes to the operating system */ @@ -513,15 +505,16 @@ buf_flush_or_remove_page( buf_pool_mutex_enter(buf_pool); - processed = true; + buf_flush_list_mutex_enter(buf_pool); + + return(true); + } else { - /* Not ready for flush. It can't be IO fixed because we - checked for that at the start of the function. It must - be buffer fixed. */ - ut_ad(bpage->buf_fix_count > 0); - mutex_exit(block_mutex); + processed = false; } + mutex_exit(block_mutex); + buf_flush_list_mutex_enter(buf_pool); ut_ad(!mutex_own(block_mutex)); @@ -1684,8 +1677,6 @@ buf_LRU_add_block_low( { buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); - ut_ad(buf_pool); - ut_ad(bpage); ut_ad(buf_pool_mutex_own(buf_pool)); ut_a(buf_page_in_file(bpage)); @@ -1835,7 +1826,7 @@ buf_LRU_free_page( if (!buf_page_can_relocate(bpage)) { - /* Do not free buffer-fixed or I/O-fixed blocks. */ + /* Do not free buffer fixed or I/O-fixed blocks. */ goto func_exit; } @@ -1850,12 +1841,10 @@ buf_LRU_free_page( if (bpage->oldest_modification) { goto func_exit; } - } else if ((bpage->oldest_modification) - && (buf_page_get_state(bpage) - != BUF_BLOCK_FILE_PAGE)) { + } else if (bpage->oldest_modification > 0 + && buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) { - ut_ad(buf_page_get_state(bpage) - == BUF_BLOCK_ZIP_DIRTY); + ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_DIRTY); func_exit: rw_lock_x_unlock(hash_lock); @@ -1915,10 +1904,8 @@ func_exit: rw_lock_x_lock(hash_lock); mutex_enter(block_mutex); - ut_a(!buf_page_hash_get_low(buf_pool, - bpage->space, - bpage->offset, - fold)); + ut_a(!buf_page_hash_get_low( + buf_pool, b->space, b->offset, fold)); b->state = b->oldest_modification ? BUF_BLOCK_ZIP_DIRTY @@ -2333,6 +2320,11 @@ buf_LRU_block_remove_hashed( UNIV_PAGE_SIZE); buf_page_set_state(bpage, BUF_BLOCK_REMOVE_HASH); + if (buf_pool->flush_rbt == NULL) { + bpage->space = ULINT32_UNDEFINED; + bpage->offset = ULINT32_UNDEFINED; + } + /* Question: If we release bpage and hash mutex here then what protects us against: 1) Some other thread buffer fixing this page diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index eba5417dc76..ff892749d4f 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2013, 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 @@ -270,6 +270,12 @@ dict_build_table_def_step( thr_get_trx(thr)->table_id = table->id; + /* Always set this bit for all new created tables */ + DICT_TF2_FLAG_SET(table, DICT_TF2_FTS_AUX_HEX_NAME); + DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name", + DICT_TF2_FLAG_UNSET(table, + DICT_TF2_FTS_AUX_HEX_NAME);); + if (use_tablespace) { /* This table will not use the system tablespace. Get a new space id. */ diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index d16296179b0..bbae608efdb 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -121,19 +121,6 @@ UNIV_INTERN mysql_pfs_key_t dict_foreign_err_mutex_key; /** Identifies generated InnoDB foreign key names */ static char dict_ibfk[] = "_ibfk_"; -/** array of rw locks protecting -dict_table_t::stat_initialized -dict_table_t::stat_n_rows (*) -dict_table_t::stat_clustered_index_size -dict_table_t::stat_sum_of_other_index_sizes -dict_table_t::stat_modified_counter (*) -dict_table_t::indexes*::stat_n_diff_key_vals[] -dict_table_t::indexes*::stat_index_size -dict_table_t::indexes*::stat_n_leaf_pages -(*) those are not always protected for performance reasons */ -#define DICT_TABLE_STATS_LATCHES_SIZE 64 -static rw_lock_t dict_table_stats_latches[DICT_TABLE_STATS_LATCHES_SIZE]; - /*******************************************************************//** Tries to find column names for the index and sets the col field of the index. @@ -332,32 +319,31 @@ dict_mutex_exit_for_mysql(void) mutex_exit(&(dict_sys->mutex)); } -/** Get the latch that protects the stats of a given table */ -#define GET_TABLE_STATS_LATCH(table) \ - (&dict_table_stats_latches[ut_fold_ull((ib_uint64_t) table) \ - % DICT_TABLE_STATS_LATCHES_SIZE]) - /**********************************************************************//** -Lock the appropriate latch to protect a given table's statistics. -table->id is used to pick the corresponding latch from a global array of -latches. */ +Lock the appropriate latch to protect a given table's statistics. */ UNIV_INTERN void dict_table_stats_lock( /*==================*/ - const dict_table_t* table, /*!< in: table */ - ulint latch_mode) /*!< in: RW_S_LATCH or - RW_X_LATCH */ + dict_table_t* table, /*!< in: table */ + ulint latch_mode) /*!< in: RW_S_LATCH or RW_X_LATCH */ { ut_ad(table != NULL); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + if (table->stats_latch == NULL) { + /* This is a dummy table object that is private in the current + thread and is not shared between multiple threads, thus we + skip any locking. */ + return; + } + switch (latch_mode) { case RW_S_LATCH: - rw_lock_s_lock(GET_TABLE_STATS_LATCH(table)); + rw_lock_s_lock(table->stats_latch); break; case RW_X_LATCH: - rw_lock_x_lock(GET_TABLE_STATS_LATCH(table)); + rw_lock_x_lock(table->stats_latch); break; case RW_NO_LATCH: /* fall through */ @@ -372,19 +358,26 @@ UNIV_INTERN void dict_table_stats_unlock( /*====================*/ - const dict_table_t* table, /*!< in: table */ - ulint latch_mode) /*!< in: RW_S_LATCH or + dict_table_t* table, /*!< in: table */ + ulint latch_mode) /*!< in: RW_S_LATCH or RW_X_LATCH */ { ut_ad(table != NULL); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + if (table->stats_latch == NULL) { + /* This is a dummy table object that is private in the current + thread and is not shared between multiple threads, thus we + skip any locking. */ + return; + } + switch (latch_mode) { case RW_S_LATCH: - rw_lock_s_unlock(GET_TABLE_STATS_LATCH(table)); + rw_lock_s_unlock(table->stats_latch); break; case RW_X_LATCH: - rw_lock_x_unlock(GET_TABLE_STATS_LATCH(table)); + rw_lock_x_unlock(table->stats_latch); break; case RW_NO_LATCH: /* fall through */ @@ -880,8 +873,6 @@ void dict_init(void) /*===========*/ { - int i; - dict_sys = static_cast(mem_zalloc(sizeof(*dict_sys))); mutex_create(dict_sys_mutex_key, &dict_sys->mutex, SYNC_DICT); @@ -902,11 +893,6 @@ dict_init(void) mutex_create(dict_foreign_err_mutex_key, &dict_foreign_err_mutex, SYNC_NO_ORDER_CHECK); } - - for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) { - rw_lock_create(dict_table_stats_latch_key, - &dict_table_stats_latches[i], SYNC_INDEX_TREE); - } } /**********************************************************************//** @@ -5968,6 +5954,17 @@ dict_table_check_for_dup_indexes( } #endif /* UNIV_DEBUG */ +/** Auxiliary macro used inside dict_table_schema_check(). */ +#define CREATE_TYPES_NAMES() \ + dtype_sql_name((unsigned) req_schema->columns[i].mtype, \ + (unsigned) req_schema->columns[i].prtype_mask, \ + (unsigned) req_schema->columns[i].len, \ + req_type, sizeof(req_type)); \ + dtype_sql_name(table->cols[j].mtype, \ + table->cols[j].prtype, \ + table->cols[j].len, \ + actual_type, sizeof(actual_type)) + /*********************************************************************//** Checks whether a table exists and whether it has the given structure. The table must have the same number of columns with the same names and @@ -5987,6 +5984,8 @@ dict_table_schema_check( size_t errstr_sz) /*!< in: errstr size */ { char buf[MAX_FULL_NAME_LEN]; + char req_type[64]; + char actual_type[64]; dict_table_t* table; ulint i; @@ -6038,9 +6037,6 @@ dict_table_schema_check( for (i = 0; i < req_schema->n_cols; i++) { ulint j; - char req_type[64]; - char actual_type[64]; - /* check if i'th column is the same in both arrays */ if (innobase_strcasecmp(req_schema->columns[i].name, dict_table_get_col_name(table, i)) == 0) { @@ -6082,19 +6078,11 @@ dict_table_schema_check( /* we found a column with the same name on j'th position, compare column types and flags */ - dtype_sql_name(req_schema->columns[i].mtype, - req_schema->columns[i].prtype_mask, - req_schema->columns[i].len, - req_type, sizeof(req_type)); - - dtype_sql_name(table->cols[j].mtype, - table->cols[j].prtype, - table->cols[j].len, - actual_type, sizeof(actual_type)); - /* check length for exact match */ if (req_schema->columns[i].len != table->cols[j].len) { + CREATE_TYPES_NAMES(); + ut_snprintf(errstr, errstr_sz, "Column %s in table %s is %s " "but should be %s (length mismatch).", @@ -6117,6 +6105,8 @@ dict_table_schema_check( !(req_schema->columns[i].mtype == DATA_INT && table->cols[j].mtype == DATA_FIXBINARY)) { + CREATE_TYPES_NAMES(); + ut_snprintf(errstr, errstr_sz, "Column %s in table %s is %s " "but should be %s (type mismatch).", @@ -6134,6 +6124,8 @@ dict_table_schema_check( & req_schema->columns[i].prtype_mask) != req_schema->columns[i].prtype_mask) { + CREATE_TYPES_NAMES(); + ut_snprintf(errstr, errstr_sz, "Column %s in table %s is %s " "but should be %s (flags mismatch).", @@ -6292,10 +6284,6 @@ dict_close(void) mem_free(dict_sys); dict_sys = NULL; - - for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) { - rw_lock_free(&dict_table_stats_latches[i]); - } } #ifdef UNIV_DEBUG diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index 81ab765b524..c8defc1d021 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -1092,10 +1092,34 @@ loop: case DICT_CHECK_ALL_LOADED: /* All tablespaces should have been found in fil_load_single_table_tablespaces(). */ - - fil_space_for_table_exists_in_mem( + if (fil_space_for_table_exists_in_mem( space_id, name, TRUE, !(is_temp || discarded), - false, NULL, 0); + false, NULL, 0) + && !(is_temp || discarded)) { + /* If user changes the path of .ibd files in + *.isl files before doing crash recovery , + then this leads to inconsistency in + SYS_DATAFILES system table because the + tables are loaded from the updated path + but the SYS_DATAFILES still points to the + old path.Therefore after crash recovery + update SYS_DATAFILES with the updated path.*/ + ut_ad(space_id); + ut_ad(recv_needed_recovery); + char *dict_path = dict_get_first_path(space_id, + name); + char *remote_path = fil_read_link_file(name); + if(dict_path && remote_path) { + if(strcmp(dict_path,remote_path)) { + dict_update_filepath(space_id, + remote_path); + } + } + if(dict_path) + mem_free(dict_path); + if(remote_path) + mem_free(remote_path); + } break; case DICT_CHECK_SOME_LOADED: diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 565a46b1832..60daeea3a96 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -95,6 +95,10 @@ dict_mem_table_create( ut_d(table->magic_n = DICT_TABLE_MAGIC_N); + table->stats_latch = new rw_lock_t; + rw_lock_create(dict_table_stats_latch_key, table->stats_latch, + SYNC_INDEX_TREE); + #ifndef UNIV_HOTBACKUP table->autoinc_lock = static_cast( mem_heap_alloc(heap, lock_get_size())); @@ -149,6 +153,10 @@ dict_mem_table_free( #ifndef UNIV_HOTBACKUP mutex_free(&(table->autoinc_mutex)); #endif /* UNIV_HOTBACKUP */ + + rw_lock_free(table->stats_latch); + delete table->stats_latch; + ut_free(table->name); mem_heap_free(table->heap); } diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index 8bf02f9785c..68c02a301cd 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -400,6 +400,11 @@ dict_stats_table_clone_create( t->corrupted = table->corrupted; + /* This private object "t" is not shared with other threads, so + we do not need the stats_latch. The lock/unlock routines will do + nothing if stats_latch is NULL. */ + t->stats_latch = NULL; + UT_LIST_INIT(t->indexes); for (index = dict_table_get_first_index(table); @@ -731,7 +736,7 @@ static dict_table_t* dict_stats_snapshot_create( /*=======================*/ - const dict_table_t* table) /*!< in: table whose stats to copy */ + dict_table_t* table) /*!< in: table whose stats to copy */ { mutex_enter(&dict_sys->mutex); @@ -2131,8 +2136,16 @@ dict_stats_save_index_stat( ret = dict_stats_exec_sql( pinfo, - "PROCEDURE INDEX_STATS_SAVE_INSERT () IS\n" + "PROCEDURE INDEX_STATS_SAVE () IS\n" "BEGIN\n" + + "DELETE FROM \"" INDEX_STATS_NAME "\"\n" + "WHERE\n" + "database_name = :database_name AND\n" + "table_name = :table_name AND\n" + "index_name = :index_name AND\n" + "stat_name = :stat_name;\n" + "INSERT INTO \"" INDEX_STATS_NAME "\"\n" "VALUES\n" "(\n" @@ -2147,47 +2160,6 @@ dict_stats_save_index_stat( ");\n" "END;"); - if (ret == DB_DUPLICATE_KEY) { - - pinfo = pars_info_create(); - pars_info_add_str_literal(pinfo, "database_name", db_utf8); - pars_info_add_str_literal(pinfo, "table_name", table_utf8); - UNIV_MEM_ASSERT_RW_ABORT(index->name, strlen(index->name)); - pars_info_add_str_literal(pinfo, "index_name", index->name); - UNIV_MEM_ASSERT_RW_ABORT(&last_update, 4); - pars_info_add_int4_literal(pinfo, "last_update", last_update); - UNIV_MEM_ASSERT_RW_ABORT(stat_name, strlen(stat_name)); - pars_info_add_str_literal(pinfo, "stat_name", stat_name); - UNIV_MEM_ASSERT_RW_ABORT(&stat_value, 8); - pars_info_add_ull_literal(pinfo, "stat_value", stat_value); - if (sample_size != NULL) { - UNIV_MEM_ASSERT_RW_ABORT(sample_size, 8); - pars_info_add_ull_literal(pinfo, "sample_size", *sample_size); - } else { - pars_info_add_literal(pinfo, "sample_size", NULL, - UNIV_SQL_NULL, DATA_FIXBINARY, 0); - } - UNIV_MEM_ASSERT_RW_ABORT(stat_description, strlen(stat_description)); - pars_info_add_str_literal(pinfo, "stat_description", - stat_description); - - ret = dict_stats_exec_sql( - pinfo, - "PROCEDURE INDEX_STATS_SAVE_UPDATE () IS\n" - "BEGIN\n" - "UPDATE \"" INDEX_STATS_NAME "\" SET\n" - "last_update = :last_update,\n" - "stat_value = :stat_value,\n" - "sample_size = :sample_size,\n" - "stat_description = :stat_description\n" - "WHERE\n" - "database_name = :database_name AND\n" - "table_name = :table_name AND\n" - "index_name = :index_name AND\n" - "stat_name = :stat_name;\n" - "END;"); - } - if (ret != DB_SUCCESS) { char buf_table[MAX_FULL_NAME_LEN]; char buf_index[MAX_FULL_NAME_LEN]; @@ -2205,14 +2177,18 @@ dict_stats_save_index_stat( return(ret); } -/*********************************************************************//** -Save the table's statistics into the persistent statistics storage. +/** Save the table's statistics into the persistent statistics storage. +@param[in] table_orig table whose stats to save +@param[in] only_for_index if this is non-NULL, then stats for indexes +that are not equal to it will not be saved, if NULL, then all +indexes' stats are saved @return DB_SUCCESS or error code */ static dberr_t dict_stats_save( /*============*/ - dict_table_t* table_orig) /*!< in: table */ + dict_table_t* table_orig, + const index_id_t* only_for_index) { pars_info_t* pinfo; lint now; @@ -2234,26 +2210,27 @@ dict_stats_save( lint */ now = (lint) ut_time(); -#define PREPARE_PINFO_FOR_TABLE_SAVE(p, t, n) \ - do { \ - pars_info_add_str_literal((p), "database_name", db_utf8); \ - pars_info_add_str_literal((p), "table_name", table_utf8); \ - pars_info_add_int4_literal((p), "last_update", (n)); \ - pars_info_add_ull_literal((p), "n_rows", (t)->stat_n_rows); \ - pars_info_add_ull_literal((p), "clustered_index_size", \ - (t)->stat_clustered_index_size); \ - pars_info_add_ull_literal((p), "sum_of_other_index_sizes", \ - (t)->stat_sum_of_other_index_sizes); \ - } while(false); - pinfo = pars_info_create(); - PREPARE_PINFO_FOR_TABLE_SAVE(pinfo, table, now); + pars_info_add_str_literal(pinfo, "database_name", db_utf8); + pars_info_add_str_literal(pinfo, "table_name", table_utf8); + pars_info_add_int4_literal(pinfo, "last_update", now); + pars_info_add_ull_literal(pinfo, "n_rows", table->stat_n_rows); + pars_info_add_ull_literal(pinfo, "clustered_index_size", + table->stat_clustered_index_size); + pars_info_add_ull_literal(pinfo, "sum_of_other_index_sizes", + table->stat_sum_of_other_index_sizes); ret = dict_stats_exec_sql( pinfo, - "PROCEDURE TABLE_STATS_SAVE_INSERT () IS\n" + "PROCEDURE TABLE_STATS_SAVE () IS\n" "BEGIN\n" + + "DELETE FROM \"" TABLE_STATS_NAME "\"\n" + "WHERE\n" + "database_name = :database_name AND\n" + "table_name = :table_name;\n" + "INSERT INTO \"" TABLE_STATS_NAME "\"\n" "VALUES\n" "(\n" @@ -2266,27 +2243,6 @@ dict_stats_save( ");\n" "END;"); - if (ret == DB_DUPLICATE_KEY) { - pinfo = pars_info_create(); - - PREPARE_PINFO_FOR_TABLE_SAVE(pinfo, table, now); - - ret = dict_stats_exec_sql( - pinfo, - "PROCEDURE TABLE_STATS_SAVE_UPDATE () IS\n" - "BEGIN\n" - "UPDATE \"" TABLE_STATS_NAME "\" SET\n" - "last_update = :last_update,\n" - "n_rows = :n_rows,\n" - "clustered_index_size = :clustered_index_size,\n" - "sum_of_other_index_sizes = " - " :sum_of_other_index_sizes\n" - "WHERE\n" - "database_name = :database_name AND\n" - "table_name = :table_name;\n" - "END;"); - } - if (ret != DB_SUCCESS) { char buf[MAX_FULL_NAME_LEN]; ut_print_timestamp(stderr); @@ -2304,6 +2260,10 @@ dict_stats_save( index != NULL; index = dict_table_get_next_index(index)) { + if (only_for_index != NULL && index->id != *only_for_index) { + continue; + } + if (dict_stats_should_ignore_index(index)) { continue; } @@ -2860,7 +2820,7 @@ dict_stats_update_for_index( dict_table_stats_lock(index->table, RW_X_LATCH); dict_stats_analyze_index(index); dict_table_stats_unlock(index->table, RW_X_LATCH); - dict_stats_save(index->table); + dict_stats_save(index->table, &index->id); DBUG_VOID_RETURN; } /* else */ @@ -2955,7 +2915,7 @@ dict_stats_update( return(err); } - err = dict_stats_save(table); + err = dict_stats_save(table, NULL); return(err); } @@ -2988,7 +2948,7 @@ dict_stats_update( if (dict_stats_persistent_storage_check(false)) { - return(dict_stats_save(table)); + return(dict_stats_save(table, NULL)); } return(DB_STATS_DO_NOT_EXIST); @@ -3834,7 +3794,7 @@ test_dict_stats_save() index2_stat_n_sample_sizes[2] = TEST_IDX2_N_DIFF3_SAMPLE_SIZE; index2_stat_n_sample_sizes[3] = TEST_IDX2_N_DIFF4_SAMPLE_SIZE; - ret = dict_stats_save(&table); + ret = dict_stats_save(&table, NULL); ut_a(ret == DB_SUCCESS); diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 11b28d78f21..6254b3b7e9f 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -2383,27 +2383,21 @@ fil_op_log_parse_or_replay( break; case MLOG_FILE_RENAME: - /* We do the rename based on space id, not old file name; - this should guarantee that after the log replay each .ibd file - has the correct name for the latest log sequence number; the - proof is left as an exercise :) */ + /* In order to replay the rename, the following must hold: + * The new name is not already used. + * A tablespace is open in memory with the old name. + * The space ID for that tablepace matches this log entry. + This will prevent unintended renames during recovery. */ - if (fil_tablespace_exists_in_mem(space_id)) { + if (fil_get_space_id_for_table(new_name) == ULINT_UNDEFINED + && space_id == fil_get_space_id_for_table(name)) { /* Create the database directory for the new name, if it does not exist yet */ fil_create_directory_for_tablename(new_name); - /* Rename the table if there is not yet a tablespace - with the same name */ - - if (fil_get_space_id_for_table(new_name) - == ULINT_UNDEFINED) { - /* We do not care about the old name, that - is why we pass NULL as the first argument. */ - if (!fil_rename_tablespace(NULL, space_id, - new_name, NULL)) { - ut_error; - } + if (!fil_rename_tablespace(name, space_id, + new_name, NULL)) { + ut_error; } } @@ -4021,6 +4015,175 @@ fil_make_ibbackup_old_name( } #endif /* UNIV_HOTBACKUP */ + +/*******************************************************************//** +Determine the space id of the given file descriptor by reading a few +pages from the beginning of the .ibd file. +@return true if space id was successfully identified, or false. */ +static +bool +fil_user_tablespace_find_space_id( +/*==============================*/ + fsp_open_info* fsp) /* in/out: contains file descriptor, which is + used as input. contains space_id, which is + the output */ +{ + bool st; + os_offset_t file_size; + + file_size = os_file_get_size(fsp->file); + + if (file_size == (os_offset_t) -1) { + ib_logf(IB_LOG_LEVEL_ERROR, "Could not get file size: %s", + fsp->filepath); + return(false); + } + + /* Assuming a page size, read the space_id from each page and store it + in a map. Find out which space_id is agreed on by majority of the + pages. Choose that space_id. */ + for (ulint page_size = UNIV_ZIP_SIZE_MIN; + page_size <= UNIV_PAGE_SIZE_MAX; page_size <<= 1) { + + /* map[space_id] = count of pages */ + std::map verify; + + ulint page_count = 64; + ulint valid_pages = 0; + + /* Adjust the number of pages to analyze based on file size */ + while ((page_count * page_size) > file_size) { + --page_count; + } + + ib_logf(IB_LOG_LEVEL_INFO, "Page size:%lu Pages to analyze:" + "%lu", page_size, page_count); + + byte* buf = static_cast(ut_malloc(2*page_size)); + byte* page = static_cast(ut_align(buf, page_size)); + + for (ulint j = 0; j < page_count; ++j) { + + st = os_file_read(fsp->file, page, (j* page_size), page_size); + + if (!st) { + ib_logf(IB_LOG_LEVEL_INFO, + "READ FAIL: page_no:%lu", j); + continue; + } + + bool uncompressed_ok = false; + + /* For uncompressed pages, the page size must be equal + to UNIV_PAGE_SIZE. */ + if (page_size == UNIV_PAGE_SIZE) { + uncompressed_ok = !buf_page_is_corrupted( + false, page, 0); + } + + bool compressed_ok = !buf_page_is_corrupted( + false, page, page_size); + + if (uncompressed_ok || compressed_ok) { + + ulint space_id = mach_read_from_4(page + + FIL_PAGE_SPACE_ID); + + if (space_id > 0) { + ib_logf(IB_LOG_LEVEL_INFO, + "VALID: space:%lu " + "page_no:%lu page_size:%lu", + space_id, j, page_size); + verify[space_id]++; + ++valid_pages; + } + } + } + + ut_free(buf); + + ib_logf(IB_LOG_LEVEL_INFO, "Page size: %lu, Possible space_id " + "count:%lu", page_size, verify.size()); + + const ulint pages_corrupted = 3; + for (ulint missed = 0; missed <= pages_corrupted; ++missed) { + + for (std::map::iterator + m = verify.begin(); m != verify.end(); ++m ) { + + ib_logf(IB_LOG_LEVEL_INFO, "space_id:%lu, " + "Number of pages matched: %lu/%lu " + "(%lu)", m->first, m->second, + valid_pages, page_size); + + if (m->second == (valid_pages - missed)) { + + ib_logf(IB_LOG_LEVEL_INFO, + "Chosen space:%lu\n", m->first); + + fsp->id = m->first; + return(true); + } + } + + } + } + + return(false); +} + +/*******************************************************************//** +Finds the page 0 of the given space id from the double write buffer, and +copies it to the corresponding .ibd file. +@return true if copy was successful, or false. */ +static +bool +fil_user_tablespace_restore_page0( +/*==============================*/ + fsp_open_info* fsp) /* in: contains space id and .ibd file + information */ +{ + bool err; + ulint flags; + ulint zip_size; + ulint page_no; + ulint page_size; + ulint buflen; + byte* page; + + ib_logf(IB_LOG_LEVEL_INFO, "Restoring first page of tablespace %lu", + fsp->id); + + if (fsp->id == 0) { + err = false; + goto out; + } + + // find if double write buffer has page0 of given space id + page = recv_sys->dblwr.find_first_page(fsp->id); + + if (!page) { + err = false; + goto out; + } + + flags = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page); + zip_size = fsp_flags_get_zip_size(flags); + page_no = page_get_page_no(page); + page_size = fsp_flags_get_page_size(flags); + + ut_ad(page_no == 0); + + buflen = zip_size ? zip_size: page_size; + + ib_logf(IB_LOG_LEVEL_INFO, "Writing %lu bytes into file: %s", + buflen, fsp->filepath); + + err = os_file_write(fsp->filepath, fsp->file, page, 0, buflen); +out: + return(err); +} + /********************************************************************//** Opens an .ibd file and adds the associated single-table tablespace to the InnoDB fil0fil.cc data structures. @@ -4032,6 +4195,10 @@ fil_validate_single_table_tablespace( const char* tablename, /*!< in: database/tablename */ fsp_open_info* fsp) /*!< in/out: tablespace info */ { + bool restore_attempted = false; + +check_first_page: + fsp->success = TRUE; if (const char* check_msg = fil_read_first_page( fsp->file, FALSE, &fsp->flags, &fsp->id, #ifdef UNIV_LOG_ARCHIVE @@ -4042,6 +4209,19 @@ fil_validate_single_table_tablespace( "%s in tablespace %s (table %s)", check_msg, fsp->filepath, tablename); fsp->success = FALSE; + } + + if (!fsp->success) { + if (!restore_attempted) { + if (!fil_user_tablespace_find_space_id(fsp)) { + return; + } + restore_attempted = true; + if (!fil_user_tablespace_restore_page0(fsp)) { + return; + } + goto check_first_page; + } return; } @@ -4159,7 +4339,7 @@ fil_load_single_table_tablespace( /* Try to open the tablespace in the datadir. */ def.file = os_file_create_simple_no_error_handling( innodb_file_data_key, def.filepath, OS_FILE_OPEN, - OS_FILE_READ_ONLY, &def.success); + OS_FILE_READ_WRITE, &def.success); /* Read the first page of the remote tablespace */ if (def.success) { diff --git a/storage/innobase/fts/fts0ast.cc b/storage/innobase/fts/fts0ast.cc index 3a03fc63303..d6c19c0050a 100644 --- a/storage/innobase/fts/fts0ast.cc +++ b/storage/innobase/fts/fts0ast.cc @@ -112,9 +112,11 @@ fts_ast_create_node_term( if (str.f_n_char > 0) { /* If the subsequent term (after the first one)'s size - is less than fts_min_token_size, we shall ignore - that. This is to make consistent with MyISAM behavior */ - if (first_node && (str.f_n_char < fts_min_token_size)) { + is less than fts_min_token_size or the term is greater + than fts_max_token_size, we shall ignore that. This is + to make consistent with MyISAM behavior */ + if ((first_node && (str.f_n_char < fts_min_token_size)) + || str.f_n_char > fts_max_token_size) { continue; } @@ -394,6 +396,10 @@ fts_ast_term_set_distance( ulint distance) /*!< in: the text proximity distance */ { + if (node == NULL) { + return; + } + ut_a(node->type == FTS_AST_TEXT); ut_a(node->text.distance == ULINT_UNDEFINED); @@ -551,14 +557,6 @@ fts_ast_visit( break; - case FTS_AST_SUBEXP_LIST: - if (visit_pass != FTS_PASS_FIRST) { - break; - } - - error = fts_ast_visit_sub_exp(node, visitor, arg); - break; - case FTS_AST_OPER: oper = node->oper; oper_node = node; diff --git a/storage/innobase/fts/fts0blex.cc b/storage/innobase/fts/fts0blex.cc index dccedac0212..6082261e74c 100644 --- a/storage/innobase/fts/fts0blex.cc +++ b/storage/innobase/fts/fts0blex.cc @@ -305,9 +305,9 @@ YY_BUFFER_STATE fts0b_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner YY_BUFFER_STATE fts0b_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); YY_BUFFER_STATE fts0b_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); -void *fts0balloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); -void *fts0brealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); -void fts0bfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +void *fts0balloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +void *fts0brealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +void fts0bfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); #define yy_new_buffer fts0b_create_buffer @@ -347,7 +347,7 @@ typedef int yy_state_type; static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); static int yy_get_next_buffer (yyscan_t yyscanner ); -static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. @@ -579,11 +579,11 @@ extern int fts0bwrap (yyscan_t yyscanner ); #endif #ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); +static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); +static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); #endif #ifndef YY_NO_INPUT @@ -1609,9 +1609,9 @@ YY_BUFFER_STATE fts0b_scan_bytes (yyconst char * yybytes, int _yybytes_len , y #define YY_EXIT_FAILURE 2 #endif -static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { - (void) fprintf( stderr, "%s\n", msg ); + (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } @@ -1910,7 +1910,7 @@ int fts0blex_destroy (yyscan_t yyscanner) */ #ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { register int i; for ( i = 0; i < n; ++i ) @@ -1919,7 +1919,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { register int n; for ( n = 0; s[n]; ++n ) @@ -1929,12 +1929,12 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribu } #endif -void *fts0balloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +void *fts0balloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { return (void *) malloc( size ); } -void *fts0brealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +void *fts0brealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those @@ -1946,7 +1946,7 @@ void *fts0brealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __at return (void *) realloc( (char *) ptr, size ); } -void fts0bfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +void fts0bfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { free( (char *) ptr ); /* see fts0brealloc() for (char *) cast */ } diff --git a/storage/innobase/fts/fts0config.cc b/storage/innobase/fts/fts0config.cc index c5cf38ca7f9..5b4ae5c39f7 100644 --- a/storage/innobase/fts/fts0config.cc +++ b/storage/innobase/fts/fts0config.cc @@ -151,7 +151,9 @@ fts_config_create_index_param_name( strcpy(name, param); name[len] = '_'; - fts_write_object_id(index->id, name + len + 1); + fts_write_object_id(index->id, name + len + 1, + DICT_TF2_FLAG_IS_SET(index->table, + DICT_TF2_FTS_AUX_HEX_NAME)); return(name); } diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 41f20c1dbb9..b12f3de7ff2 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -1608,7 +1608,8 @@ fts_rename_aux_tables( new_name, old_table_name, trx); DBUG_EXECUTE_IF("fts_rename_failure", - err = DB_DEADLOCK;); + err = DB_DEADLOCK; + fts_sql_rollback(trx);); mem_free(old_table_name); @@ -2018,7 +2019,7 @@ fts_create_index_tables_low( fts_table.index_id = index->id; fts_table.table_id = table_id; fts_table.parent = table_name; - fts_table.table = NULL; + fts_table.table = index->table; #ifdef FTS_DOC_STATS_DEBUG char* sql; @@ -4479,7 +4480,7 @@ fts_sync_table( ut_ad(table->fts); - if (table->fts->cache) { + if (!dict_table_is_discarded(table) && table->fts->cache) { err = fts_sync(table->fts->cache->sync); } @@ -4506,15 +4507,11 @@ fts_process_token( fts_string_t str; ulint offset = 0; fts_doc_t* result_doc; - byte buf[FTS_MAX_WORD_LEN + 1]; - - str.f_str = buf; /* Determine where to save the result. */ result_doc = (result) ? result : doc; /* The length of a string in characters is set here only. */ - ret = innobase_mysql_fts_get_token( doc->charset, doc->text.f_str + start_pos, doc->text.f_str + doc->text.f_len, &str, &offset); @@ -4545,6 +4542,7 @@ fts_process_token( (char*) t_str.f_str, t_str.f_len); t_str.f_len = newlen; + t_str.f_str[newlen] = 0; /* Add the word to the document statistics. If the word hasn't been seen before we create a new entry for it. */ @@ -5797,7 +5795,7 @@ fts_is_aux_table_name( my_name[len] = 0; end = my_name + len; - ptr = static_cast(memchr(my_name, '/', len)); + ptr = static_cast(memchr(my_name, '/', len)); if (ptr != NULL) { /* We will start the match after the '/' */ @@ -5940,6 +5938,374 @@ fts_read_tables( return(TRUE); } +/******************************************************************//** +Callback that sets a hex formatted FTS table's flags2 in +SYS_TABLES. The flags is stored in MIX_LEN column. +@return FALSE if all OK */ +static +ibool +fts_set_hex_format( +/*===============*/ + void* row, /*!< in: sel_node_t* */ + void* user_arg) /*!< in: bool set/unset flag */ +{ + sel_node_t* node = static_cast(row); + dfield_t* dfield = que_node_get_val(node->select_list); + + ut_ad(dtype_get_mtype(dfield_get_type(dfield)) == DATA_INT); + ut_ad(dfield_get_len(dfield) == sizeof(ib_uint32_t)); + /* There should be at most one matching record. So the value + must be the default value. */ + ut_ad(mach_read_from_4(static_cast(user_arg)) + == ULINT32_UNDEFINED); + + ulint flags2 = mach_read_from_4( + static_cast(dfield_get_data(dfield))); + + flags2 |= DICT_TF2_FTS_AUX_HEX_NAME; + + mach_write_to_4(static_cast(user_arg), flags2); + + return(FALSE); +} + +/*****************************************************************//** +Update the DICT_TF2_FTS_AUX_HEX_NAME flag in SYS_TABLES. +@return DB_SUCCESS or error code. */ +UNIV_INTERN +dberr_t +fts_update_hex_format_flag( +/*=======================*/ + trx_t* trx, /*!< in/out: transaction that + covers the update */ + table_id_t table_id, /*!< in: Table for which we want + to set the root table->flags2 */ + bool dict_locked) /*!< in: set to true if the + caller already owns the + dict_sys_t::mutex. */ +{ + pars_info_t* info; + ib_uint32_t flags2; + + static const char sql[] = + "PROCEDURE UPDATE_HEX_FORMAT_FLAG() IS\n" + "DECLARE FUNCTION my_func;\n" + "DECLARE CURSOR c IS\n" + " SELECT MIX_LEN " + " FROM SYS_TABLES " + " WHERE ID = :table_id FOR UPDATE;" + "\n" + "BEGIN\n" + "OPEN c;\n" + "WHILE 1 = 1 LOOP\n" + " FETCH c INTO my_func();\n" + " IF c % NOTFOUND THEN\n" + " EXIT;\n" + " END IF;\n" + "END LOOP;\n" + "UPDATE SYS_TABLES" + " SET MIX_LEN = :flags2" + " WHERE ID = :table_id;\n" + "CLOSE c;\n" + "END;\n"; + + flags2 = ULINT32_UNDEFINED; + + info = pars_info_create(); + + pars_info_add_ull_literal(info, "table_id", table_id); + pars_info_bind_int4_literal(info, "flags2", &flags2); + + pars_info_bind_function( + info, "my_func", fts_set_hex_format, &flags2); + + if (trx_get_dict_operation(trx) == TRX_DICT_OP_NONE) { + trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); + } + + dberr_t err = que_eval_sql(info, sql, !dict_locked, trx); + + ut_a(flags2 != ULINT32_UNDEFINED); + + return (err); +} + +#ifdef _WIN32 + +/*********************************************************************//** +Rename an aux table to HEX format. It's called when "%016llu" is used +to format an object id in table name, which only happens in Windows. */ +static __attribute__((nonnull, warn_unused_result)) +dberr_t +fts_rename_one_aux_table_to_hex_format( +/*===================================*/ + trx_t* trx, /*!< in: transaction */ + const fts_aux_table_t* aux_table, /*!< in: table info */ + const dict_table_t* parent_table) /*!< in: parent table name */ +{ + const char* ptr; + fts_table_t fts_table; + char* new_name; + dberr_t error; + + ptr = strchr(aux_table->name, '/'); + ut_a(ptr != NULL); + ++ptr; + /* Skip "FTS_", table id and underscore */ + for (ulint i = 0; i < 2; ++i) { + ptr = strchr(ptr, '_'); + ut_a(ptr != NULL); + ++ptr; + } + + fts_table.suffix = NULL; + if (aux_table->index_id == 0) { + fts_table.type = FTS_COMMON_TABLE; + + for (ulint i = 0; fts_common_tables[i] != NULL; ++i) { + if (strcmp(ptr, fts_common_tables[i]) == 0) { + fts_table.suffix = fts_common_tables[i]; + break; + } + } + } else { + fts_table.type = FTS_INDEX_TABLE; + + /* Skip index id and underscore */ + ptr = strchr(ptr, '_'); + ut_a(ptr != NULL); + ++ptr; + + for (ulint i = 0; fts_index_selector[i].value; ++i) { + if (strcmp(ptr, fts_get_suffix(i)) == 0) { + fts_table.suffix = fts_get_suffix(i); + break; + } + } + } + + ut_a(fts_table.suffix != NULL); + + fts_table.parent = parent_table->name; + fts_table.table_id = aux_table->parent_id; + fts_table.index_id = aux_table->index_id; + fts_table.table = parent_table; + + new_name = fts_get_table_name(&fts_table); + ut_ad(strcmp(new_name, aux_table->name) != 0); + + if (trx_get_dict_operation(trx) == TRX_DICT_OP_NONE) { + trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); + } + + error = row_rename_table_for_mysql(aux_table->name, new_name, trx, + FALSE); + + if (error != DB_SUCCESS) { + ib_logf(IB_LOG_LEVEL_WARN, + "Failed to rename aux table \'%s\' to " + "new format \'%s\'. ", + aux_table->name, new_name); + } else { + ib_logf(IB_LOG_LEVEL_INFO, + "Renamed aux table \'%s\' to \'%s\'.", + aux_table->name, new_name); + } + + mem_free(new_name); + + return (error); +} + +/**********************************************************************//** +Rename all aux tables of a parent table to HEX format. Also set aux tables' +flags2 and parent table's flags2 with DICT_TF2_FTS_AUX_HEX_NAME. +It's called when "%016llu" is used to format an object id in table name, +which only happens in Windows. +Note the ids in tables are correct but the names are old ambiguous ones. + +This function should make sure that either all the parent table and aux tables +are set DICT_TF2_FTS_AUX_HEX_NAME with flags2 or none of them are set */ +static __attribute__((nonnull, warn_unused_result)) +dberr_t +fts_rename_aux_tables_to_hex_format( +/*================================*/ + trx_t* trx, /*!< in: transaction */ + dict_table_t* parent_table, /*!< in: parent table */ + ib_vector_t* tables) /*!< in: aux tables to rename. */ +{ + dberr_t error; + ulint count; + + ut_ad(!DICT_TF2_FLAG_IS_SET(parent_table, DICT_TF2_FTS_AUX_HEX_NAME)); + ut_ad(!ib_vector_is_empty(tables)); + + error = fts_update_hex_format_flag(trx, parent_table->id, true); + + if (error != DB_SUCCESS) { + ib_logf(IB_LOG_LEVEL_WARN, + "Setting parent table %s to hex format failed.", + parent_table->name); + + fts_sql_rollback(trx); + return (error); + } + + DICT_TF2_FLAG_SET(parent_table, DICT_TF2_FTS_AUX_HEX_NAME); + + for (count = 0; count < ib_vector_size(tables); ++count) { + dict_table_t* table; + fts_aux_table_t* aux_table; + + aux_table = static_cast( + ib_vector_get(tables, count)); + + table = dict_table_open_on_id(aux_table->id, TRUE, + DICT_TABLE_OP_NORMAL); + + ut_ad(table != NULL); + ut_ad(!DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_AUX_HEX_NAME)); + + /* Set HEX_NAME flag here to make sure we can get correct + new table name in following function */ + DICT_TF2_FLAG_SET(table, DICT_TF2_FTS_AUX_HEX_NAME); + error = fts_rename_one_aux_table_to_hex_format(trx, + aux_table, parent_table); + /* We will rollback the trx if the error != DB_SUCCESS, + so setting the flag here is the same with setting it in + row_rename_table_for_mysql */ + DBUG_EXECUTE_IF("rename_aux_table_fail", error = DB_ERROR;); + + if (error != DB_SUCCESS) { + dict_table_close(table, TRUE, FALSE); + + ib_logf(IB_LOG_LEVEL_WARN, + "Failed to rename one aux table %s " + "Will revert all successful rename " + "operations.", aux_table->name); + + fts_sql_rollback(trx); + break; + } + + error = fts_update_hex_format_flag(trx, aux_table->id, true); + dict_table_close(table, TRUE, FALSE); + + if (error != DB_SUCCESS) { + ib_logf(IB_LOG_LEVEL_WARN, + "Setting aux table %s to hex format failed.", + aux_table->name); + + fts_sql_rollback(trx); + break; + } + } + + if (error != DB_SUCCESS) { + ut_ad(count != ib_vector_size(tables)); + /* If rename fails, thr trx would be rolled back, we can't + use it any more, we'll start a new background trx to do + the reverting. */ + ut_a(trx->state == TRX_STATE_NOT_STARTED); + bool not_rename = false; + + /* Try to revert those succesful rename operations + in order to revert the ibd file rename. */ + for (ulint i = 0; i <= count; ++i) { + dict_table_t* table; + fts_aux_table_t* aux_table; + trx_t* trx_bg; + dberr_t err; + + aux_table = static_cast( + ib_vector_get(tables, i)); + + table = dict_table_open_on_id(aux_table->id, TRUE, + DICT_TABLE_OP_NORMAL); + ut_ad(table != NULL); + + if (not_rename) { + DICT_TF2_FLAG_UNSET(table, + DICT_TF2_FTS_AUX_HEX_NAME); + } + + if (!DICT_TF2_FLAG_IS_SET(table, + DICT_TF2_FTS_AUX_HEX_NAME)) { + dict_table_close(table, TRUE, FALSE); + continue; + } + + trx_bg = trx_allocate_for_background(); + trx_bg->op_info = "Revert half done rename"; + trx_bg->dict_operation_lock_mode = RW_X_LATCH; + trx_start_for_ddl(trx_bg, TRX_DICT_OP_TABLE); + + DICT_TF2_FLAG_UNSET(table, DICT_TF2_FTS_AUX_HEX_NAME); + err = row_rename_table_for_mysql(table->name, + aux_table->name, + trx_bg, FALSE); + + trx_bg->dict_operation_lock_mode = 0; + dict_table_close(table, TRUE, FALSE); + + if (err != DB_SUCCESS) { + ib_logf(IB_LOG_LEVEL_WARN, "Failed to revert " + "table %s. Please revert manually.", + table->name); + fts_sql_rollback(trx_bg); + /* Continue to clear aux tables' flags2 */ + not_rename = true; + continue; + } + + fts_sql_commit(trx_bg); + } + + DICT_TF2_FLAG_UNSET(parent_table, DICT_TF2_FTS_AUX_HEX_NAME); + } + + return (error); +} + +/**********************************************************************//** +Convert an id, which is actually a decimal number but was regard as a HEX +from a string, to its real value. */ +static +ib_id_t +fts_fake_hex_to_dec( +/*================*/ + ib_id_t id) /*!< in: number to convert */ +{ + ib_id_t dec_id = 0; + char tmp_id[FTS_AUX_MIN_TABLE_ID_LENGTH]; + int ret; + + ret = sprintf(tmp_id, UINT64PFx, id); + ut_ad(ret == 16); + ret = sscanf(tmp_id, "%016llu", &dec_id); + ut_ad(ret == 1); + + return dec_id; +} + +/*********************************************************************//** +Compare two fts_aux_table_t parent_ids. +@return < 0 if n1 < n2, 0 if n1 == n2, > 0 if n1 > n2 */ +UNIV_INLINE +int +fts_check_aux_table_parent_id_cmp( +/*==============================*/ + const void* p1, /*!< in: id1 */ + const void* p2) /*!< in: id2 */ +{ + const fts_aux_table_t* fa1 = static_cast(p1); + const fts_aux_table_t* fa2 = static_cast(p2); + + return static_cast(fa1->parent_id - fa2->parent_id); +} + +#endif /* _WIN32 */ + /**********************************************************************//** Check and drop all orphaned FTS auxiliary tables, those that don't have a parent table or FTS index defined on them. @@ -5951,18 +6317,75 @@ fts_check_and_drop_orphaned_tables( trx_t* trx, /*!< in: transaction */ ib_vector_t* tables) /*!< in: tables to check */ { +#ifdef _WIN32 + mem_heap_t* heap; + ib_vector_t* aux_tables_to_rename; + ib_alloc_t* heap_alloc; + + heap = mem_heap_create(1024); + heap_alloc = ib_heap_allocator_create(heap); + + /* We store all aux tables belonging to the same parent table here, + and rename all these tables in a batch mode. */ + aux_tables_to_rename = ib_vector_create(heap_alloc, + sizeof(fts_aux_table_t), 128); + + /* Sort by parent_id first, in case rename will fail */ + ib_vector_sort(tables, fts_check_aux_table_parent_id_cmp); +#endif /* _WIN32 */ + for (ulint i = 0; i < ib_vector_size(tables); ++i) { - dict_table_t* table; + dict_table_t* parent_table; fts_aux_table_t* aux_table; bool drop = false; +#ifdef _WIN32 + dict_table_t* table; + fts_aux_table_t* next_aux_table = NULL; + ib_id_t orig_parent_id = 0; + bool rename = false; +#endif /* _WIN32 */ aux_table = static_cast( ib_vector_get(tables, i)); +#ifdef _WIN32 table = dict_table_open_on_id( + aux_table->id, TRUE, DICT_TABLE_OP_NORMAL); + orig_parent_id = aux_table->parent_id; + + if (table == NULL || strcmp(table->name, aux_table->name)) { + /* Skip these aux tables, which are common tables + with wrong table ids */ + if (table) { + dict_table_close(table, TRUE, FALSE); + } + + continue; + + } else if (!DICT_TF2_FLAG_IS_SET(table, + DICT_TF2_FTS_AUX_HEX_NAME)) { + + aux_table->parent_id = fts_fake_hex_to_dec( + aux_table->parent_id); + + if (aux_table->index_id != 0) { + aux_table->index_id = fts_fake_hex_to_dec( + aux_table->index_id); + } + + ut_ad(aux_table->id > aux_table->parent_id); + rename = true; + } + + if (table) { + dict_table_close(table, TRUE, FALSE); + } +#endif /* _WIN32 */ + + parent_table = dict_table_open_on_id( aux_table->parent_id, TRUE, DICT_TABLE_OP_NORMAL); - if (table == NULL || table->fts == NULL) { + if (parent_table == NULL || parent_table->fts == NULL) { drop = true; @@ -5971,7 +6394,7 @@ fts_check_and_drop_orphaned_tables( fts_t* fts; drop = true; - fts = table->fts; + fts = parent_table->fts; id = aux_table->index_id; /* Search for the FT index in the table's list. */ @@ -5979,33 +6402,28 @@ fts_check_and_drop_orphaned_tables( j < ib_vector_size(fts->indexes); ++j) { - const dict_index_t* index; + const dict_index_t* index; index = static_cast( ib_vector_getp_const(fts->indexes, j)); if (index->id == id) { - drop = false; break; } } } - if (table) { - dict_table_close(table, TRUE, FALSE); - } - if (drop) { ib_logf(IB_LOG_LEVEL_WARN, "Parent table of FTS auxiliary table %s not " "found.", aux_table->name); - dberr_t err = fts_drop_table(trx, aux_table->name); + dberr_t err = fts_drop_table(trx, aux_table->name); if (err == DB_FAIL) { - char* path; + char* path; path = fil_make_ibd_name( aux_table->name, false); @@ -6016,7 +6434,120 @@ fts_check_and_drop_orphaned_tables( mem_free(path); } } +#ifdef _WIN32 + if (!drop && rename) { + ib_vector_push(aux_tables_to_rename, aux_table); + } + + if (i + 1 < ib_vector_size(tables)) { + next_aux_table = static_cast( + ib_vector_get(tables, i + 1)); + } + + if ((next_aux_table == NULL + || orig_parent_id != next_aux_table->parent_id) + && !ib_vector_is_empty(aux_tables_to_rename)) { + /* All aux tables of parent table, whose id is + last_parent_id, have been checked, try to rename + them if necessary. We had better use a new background + trx to rename rather than the original trx, in case + any failure would cause a complete rollback. */ + dberr_t err; + trx_t* trx_rename = trx_allocate_for_background(); + trx_rename->op_info = "Rename aux tables to " + "hex format"; + trx_rename->dict_operation_lock_mode = RW_X_LATCH; + trx_start_for_ddl(trx_rename, TRX_DICT_OP_TABLE); + + err = fts_rename_aux_tables_to_hex_format(trx_rename, + parent_table, aux_tables_to_rename); + + trx_rename->dict_operation_lock_mode = 0; + + if (err != DB_SUCCESS) { + ib_logf(IB_LOG_LEVEL_WARN, + "Rollback operations on all " + "aux tables of table %s. " + "Please check why renaming aux tables " + "failed, and restart the server to " + "upgrade again to " + "get the table work.", + parent_table->name); + + fts_sql_rollback(trx_rename); + } else { + fts_sql_commit(trx_rename); + } + + trx_free_for_background(trx_rename); + ib_vector_reset(aux_tables_to_rename); + } +#else /* _WIN32 */ + if (!drop) { + dict_table_t* table; + + table = dict_table_open_on_id( + aux_table->id, TRUE, DICT_TABLE_OP_NORMAL); + if (table != NULL + && strcmp(table->name, aux_table->name)) { + dict_table_close(table, TRUE, FALSE); + table = NULL; + } + + if (table != NULL + && !DICT_TF2_FLAG_IS_SET( + table, + DICT_TF2_FTS_AUX_HEX_NAME)) { + dberr_t err = fts_update_hex_format_flag( + trx, table->id, true); + + if (err != DB_SUCCESS) { + ib_logf(IB_LOG_LEVEL_WARN, + "Setting aux table %s to hex " + "format failed.", table->name); + } else { + DICT_TF2_FLAG_SET(table, + DICT_TF2_FTS_AUX_HEX_NAME); + } + } + + if (table != NULL) { + dict_table_close(table, TRUE, FALSE); + } + + ut_ad(parent_table != NULL); + if (!DICT_TF2_FLAG_IS_SET(parent_table, + DICT_TF2_FTS_AUX_HEX_NAME)) { + dberr_t err = fts_update_hex_format_flag( + trx, parent_table->id, true); + + if (err != DB_SUCCESS) { + ib_logf(IB_LOG_LEVEL_WARN, + "Setting parent table %s of " + "FTS auxiliary %s to hex " + "format failed.", + parent_table->name, + aux_table->name); + } else { + DICT_TF2_FLAG_SET(parent_table, + DICT_TF2_FTS_AUX_HEX_NAME); + } + } + } + +#endif /* _WIN32 */ + + if (parent_table) { + dict_table_close(parent_table, TRUE, FALSE); + } } + +#ifdef _WIN32 + /* Free the memory allocated at the beginning */ + if (heap != NULL) { + mem_heap_free(heap); + } +#endif /* _WIN32 */ } /**********************************************************************//** diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index 7cdad522564..2efb5d05c21 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -1624,10 +1624,12 @@ fts_optimize_create( optim->fts_common_table.parent = table->name; optim->fts_common_table.table_id = table->id; optim->fts_common_table.type = FTS_COMMON_TABLE; + optim->fts_common_table.table = table; optim->fts_index_table.parent = table->name; optim->fts_index_table.table_id = table->id; optim->fts_index_table.type = FTS_INDEX_TABLE; + optim->fts_index_table.table = table; /* The common prefix for all this parent table's aux tables. */ optim->name_prefix = fts_get_table_name_prefix( diff --git a/storage/innobase/fts/fts0pars.cc b/storage/innobase/fts/fts0pars.cc index a4009106c83..ef361b3c9c6 100644 --- a/storage/innobase/fts/fts0pars.cc +++ b/storage/innobase/fts/fts0pars.cc @@ -467,9 +467,9 @@ static const yytype_int8 yyrhs[] = /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 79, 79, 85, 89, 99, 111, 115, 124, 128, - 132, 136, 141, 147, 152, 159, 165, 169, 173, 177, - 181, 186, 191, 197, 202 + 0, 79, 79, 85, 89, 99, 111, 119, 129, 133, + 137, 141, 146, 152, 157, 164, 170, 174, 178, 182, + 186, 191, 196, 202, 207 }; #endif @@ -1458,7 +1458,7 @@ yyreduce: (yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (2)].node)); if (!(yyval.node)) { - (yyval.node) = fts_ast_create_node_subexp_list(state, (yyvsp[(2) - (2)].node)); + (yyval.node) = (yyvsp[(2) - (2)].node); } else { fts_ast_add_node((yyval.node), (yyvsp[(2) - (2)].node)); } @@ -1471,18 +1471,23 @@ yyreduce: #line 111 "fts0pars.y" { (yyval.node) = (yyvsp[(2) - (3)].node); + + if ((yyval.node)) { + (yyval.node) = fts_ast_create_node_subexp_list(state, (yyval.node)); + } } break; case 7: /* Line 1806 of yacc.c */ -#line 115 "fts0pars.y" +#line 119 "fts0pars.y" { - (yyval.node) = fts_ast_create_node_subexp_list(state, (yyvsp[(1) - (4)].node)); + (yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (4)].node)); if ((yyvsp[(3) - (4)].node)) { - fts_ast_add_node((yyval.node), (yyvsp[(3) - (4)].node)); + fts_ast_add_node((yyval.node), + fts_ast_create_node_subexp_list(state, (yyvsp[(3) - (4)].node))); } } break; @@ -1490,7 +1495,7 @@ yyreduce: case 8: /* Line 1806 of yacc.c */ -#line 124 "fts0pars.y" +#line 129 "fts0pars.y" { (yyval.node) = (yyvsp[(1) - (1)].node); } @@ -1499,7 +1504,7 @@ yyreduce: case 9: /* Line 1806 of yacc.c */ -#line 128 "fts0pars.y" +#line 133 "fts0pars.y" { (yyval.node) = (yyvsp[(1) - (1)].node); } @@ -1508,7 +1513,7 @@ yyreduce: case 10: /* Line 1806 of yacc.c */ -#line 132 "fts0pars.y" +#line 137 "fts0pars.y" { fts_ast_term_set_wildcard((yyvsp[(1) - (2)].node)); } @@ -1517,7 +1522,7 @@ yyreduce: case 11: /* Line 1806 of yacc.c */ -#line 136 "fts0pars.y" +#line 141 "fts0pars.y" { fts_ast_term_set_distance((yyvsp[(1) - (3)].node), strtoul((yyvsp[(3) - (3)].token), NULL, 10)); free((yyvsp[(3) - (3)].token)); @@ -1527,7 +1532,7 @@ yyreduce: case 12: /* Line 1806 of yacc.c */ -#line 141 "fts0pars.y" +#line 146 "fts0pars.y" { (yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (3)].node)); fts_ast_add_node((yyval.node), (yyvsp[(2) - (3)].node)); @@ -1538,7 +1543,7 @@ yyreduce: case 13: /* Line 1806 of yacc.c */ -#line 147 "fts0pars.y" +#line 152 "fts0pars.y" { (yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (2)].node)); fts_ast_add_node((yyval.node), (yyvsp[(2) - (2)].node)); @@ -1548,7 +1553,7 @@ yyreduce: case 14: /* Line 1806 of yacc.c */ -#line 152 "fts0pars.y" +#line 157 "fts0pars.y" { (yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (4)].node)); fts_ast_add_node((yyval.node), (yyvsp[(2) - (4)].node)); @@ -1560,7 +1565,7 @@ yyreduce: case 15: /* Line 1806 of yacc.c */ -#line 159 "fts0pars.y" +#line 164 "fts0pars.y" { (yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (2)].node)); fts_ast_add_node((yyval.node), (yyvsp[(2) - (2)].node)); @@ -1570,7 +1575,7 @@ yyreduce: case 16: /* Line 1806 of yacc.c */ -#line 165 "fts0pars.y" +#line 170 "fts0pars.y" { (yyval.node) = fts_ast_create_node_oper(state, FTS_IGNORE); } @@ -1579,7 +1584,7 @@ yyreduce: case 17: /* Line 1806 of yacc.c */ -#line 169 "fts0pars.y" +#line 174 "fts0pars.y" { (yyval.node) = fts_ast_create_node_oper(state, FTS_EXIST); } @@ -1588,7 +1593,7 @@ yyreduce: case 18: /* Line 1806 of yacc.c */ -#line 173 "fts0pars.y" +#line 178 "fts0pars.y" { (yyval.node) = fts_ast_create_node_oper(state, FTS_NEGATE); } @@ -1597,7 +1602,7 @@ yyreduce: case 19: /* Line 1806 of yacc.c */ -#line 177 "fts0pars.y" +#line 182 "fts0pars.y" { (yyval.node) = fts_ast_create_node_oper(state, FTS_DECR_RATING); } @@ -1606,7 +1611,7 @@ yyreduce: case 20: /* Line 1806 of yacc.c */ -#line 181 "fts0pars.y" +#line 186 "fts0pars.y" { (yyval.node) = fts_ast_create_node_oper(state, FTS_INCR_RATING); } @@ -1614,16 +1619,6 @@ yyreduce: case 21: -/* Line 1806 of yacc.c */ -#line 186 "fts0pars.y" - { - (yyval.node) = fts_ast_create_node_term(state, (yyvsp[(1) - (1)].token)); - free((yyvsp[(1) - (1)].token)); - } - break; - - case 22: - /* Line 1806 of yacc.c */ #line 191 "fts0pars.y" { @@ -1632,10 +1627,20 @@ yyreduce: } break; + case 22: + +/* Line 1806 of yacc.c */ +#line 196 "fts0pars.y" + { + (yyval.node) = fts_ast_create_node_term(state, (yyvsp[(1) - (1)].token)); + free((yyvsp[(1) - (1)].token)); + } + break; + case 23: /* Line 1806 of yacc.c */ -#line 197 "fts0pars.y" +#line 202 "fts0pars.y" { (yyval.node) = (yyvsp[(2) - (2)].node); } @@ -1644,7 +1649,7 @@ yyreduce: case 24: /* Line 1806 of yacc.c */ -#line 202 "fts0pars.y" +#line 207 "fts0pars.y" { (yyval.node) = fts_ast_create_node_text(state, (yyvsp[(1) - (1)].token)); free((yyvsp[(1) - (1)].token)); @@ -1654,7 +1659,7 @@ yyreduce: /* Line 1806 of yacc.c */ -#line 1658 "fts0pars.cc" +#line 1663 "fts0pars.cc" default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1885,7 +1890,7 @@ yyreturn: /* Line 2067 of yacc.c */ -#line 207 "fts0pars.y" +#line 212 "fts0pars.y" /******************************************************************** diff --git a/storage/innobase/fts/fts0pars.y b/storage/innobase/fts/fts0pars.y index 73d71bc87c5..ff22e9a9873 100644 --- a/storage/innobase/fts/fts0pars.y +++ b/storage/innobase/fts/fts0pars.y @@ -101,7 +101,7 @@ expr_lst: /* Empty */ { $$ = fts_ast_create_node_list(state, $1); if (!$$) { - $$ = fts_ast_create_node_subexp_list(state, $2); + $$ = $2; } else { fts_ast_add_node($$, $2); } @@ -110,13 +110,18 @@ expr_lst: /* Empty */ { sub_expr: '(' expr_lst ')' { $$ = $2; + + if ($$) { + $$ = fts_ast_create_node_subexp_list(state, $$); + } } | prefix '(' expr_lst ')' { - $$ = fts_ast_create_node_subexp_list(state, $1); + $$ = fts_ast_create_node_list(state, $1); if ($3) { - fts_ast_add_node($$, $3); + fts_ast_add_node($$, + fts_ast_create_node_subexp_list(state, $3)); } } ; diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc index a70c742da0c..7c1b79ba35c 100644 --- a/storage/innobase/fts/fts0que.cc +++ b/storage/innobase/fts/fts0que.cc @@ -40,9 +40,7 @@ Completed 2011/7/10 Sunny and Jimmy Yang #include "fts0vlc.ic" #endif -#include #include -#include #define FTS_ELEM(t, n, i, j) (t[(i) * n + (j)]) @@ -66,8 +64,7 @@ static const double FTS_NORMALIZE_COEFF = 0.0115F; // FIXME: Need to have a generic iterator that traverses the ilist. -typedef std::map word_map_t; -typedef std::vector word_vector_t; +typedef std::vector word_vector_t; struct fts_word_freq_t; @@ -92,7 +89,7 @@ struct fts_query_t { fts_ast_node_t* cur_node; /*!< Current tree node */ - word_map_t* word_map; /*!< Matched word map for + ib_rbt_t* word_map; /*!< Matched word map for searching by word*/ word_vector_t* word_vector; /*!< Matched word vector for @@ -229,7 +226,7 @@ struct fts_doc_freq_t { /** To determine the word frequency per document. */ struct fts_word_freq_t { - byte* word; /*!< Word for which we need the freq, + fts_string_t word; /*!< Word for which we need the freq, it's allocated on the query heap */ ib_rbt_t* doc_freqs; /*!< RB Tree for storing per document @@ -257,15 +254,14 @@ static dberr_t fts_query_filter_doc_ids( /*=====================*/ - fts_query_t* query, /*!< in: query instance */ - const byte* word, /*!< in: the current word */ - fts_word_freq_t*word_freq, /*!< in/out: word frequency */ - const fts_node_t* - node, /*!< in: current FTS node */ - void* data, /*!< in: doc id ilist */ - ulint len, /*!< in: doc id ilist size */ - ibool calc_doc_count);/*!< in: whether to remember doc - count */ + fts_query_t* query, /*!< in: query instance */ + const fts_string_t* word, /*!< in: the current word */ + fts_word_freq_t* word_freq, /*!< in/out: word frequency */ + const fts_node_t* node, /*!< in: current FTS node */ + void* data, /*!< in: doc id ilist */ + ulint len, /*!< in: doc id ilist size */ + ibool calc_doc_count);/*!< in: whether to remember doc + count */ #if 0 /*****************************************************************//*** @@ -575,27 +571,41 @@ static void fts_ranking_words_add( /*==================*/ - fts_query_t* query, /*!< in: query instance */ - fts_ranking_t* ranking, /*!< in: ranking instance */ - const char* word) /*!< in: term/word to add */ + fts_query_t* query, /*!< in: query instance */ + fts_ranking_t* ranking, /*!< in: ranking instance */ + const fts_string_t* word) /*!< in: term/word to add */ { ulint pos; ulint byte_offset; ulint bit_offset; - word_map_t::iterator it; + ib_rbt_bound_t parent; - /* Note: we suppose the word map and vector are append-only */ - /* Check if need to add it to word map */ - it = query->word_map->lower_bound(word); - if (it != query->word_map->end() - && !query->word_map->key_comp()(word, it->first)) { - pos = it->second; + /* Note: we suppose the word map and vector are append-only. */ + ut_ad(query->word_vector->size() == rbt_size(query->word_map)); + + /* We use ib_rbt to simulate a map, f_n_char means position. */ + if (rbt_search(query->word_map, &parent, word) == 0) { + fts_string_t* result_word; + + result_word = rbt_value(fts_string_t, parent.last); + pos = result_word->f_n_char; + ut_ad(pos < rbt_size(query->word_map)); } else { - pos = query->word_map->size(); - query->word_map->insert(it, - std::pair(word, pos)); + /* Add the word to map. */ + fts_string_t new_word; - query->word_vector->push_back(word); + pos = rbt_size(query->word_map); + + new_word.f_str = static_cast(mem_heap_alloc(query->heap, + word->f_len + 1)); + memcpy(new_word.f_str, word->f_str, word->f_len); + new_word.f_str[word->f_len] = 0; + new_word.f_len = word->f_len; + new_word.f_n_char = pos; + + rbt_add_node(query->word_map, &parent, &new_word); + ut_ad(rbt_validate(query->word_map)); + query->word_vector->push_back(new_word); } /* Check words len */ @@ -630,7 +640,7 @@ fts_ranking_words_get_next( const fts_query_t* query, /*!< in: query instance */ fts_ranking_t* ranking,/*!< in: ranking instance */ ulint* pos, /*!< in/out: word start pos */ - byte** word) /*!< in/out: term/word to add */ + fts_string_t* word) /*!< in/out: term/word to add */ { bool ret = false; ulint max_pos = ranking->words_len * CHAR_BIT; @@ -651,7 +661,7 @@ fts_ranking_words_get_next( /* Get next word from word vector */ if (ret) { ut_ad(*pos < query->word_vector->size()); - *word = (byte*)query->word_vector->at((size_t)*pos).c_str(); + *word = query->word_vector->at((size_t)*pos); *pos += 1; } @@ -666,23 +676,22 @@ static fts_word_freq_t* fts_query_add_word_freq( /*====================*/ - fts_query_t* query, /*!< in: query instance */ - const byte* word) /*!< in: term/word to add */ + fts_query_t* query, /*!< in: query instance */ + const fts_string_t* word) /*!< in: term/word to add */ { ib_rbt_bound_t parent; /* Lookup the word in our rb tree and add if it doesn't exist. */ if (rbt_search(query->word_freqs, &parent, word) != 0) { fts_word_freq_t word_freq; - ulint len = ut_strlen((char*) word) + 1; memset(&word_freq, 0, sizeof(word_freq)); - word_freq.word = static_cast( - mem_heap_alloc(query->heap, len)); - - /* Need to copy the NUL character too. */ - memcpy(word_freq.word, word, len); + word_freq.word.f_str = static_cast( + mem_heap_alloc(query->heap, word->f_len + 1)); + memcpy(word_freq.word.f_str, word->f_str, word->f_len); + word_freq.word.f_str[word->f_len] = 0; + word_freq.word.f_len = word->f_len; word_freq.doc_count = 0; @@ -692,7 +701,7 @@ fts_query_add_word_freq( parent.last = rbt_add_node( query->word_freqs, &parent, &word_freq); - query->total_size += len + query->total_size += word->f_len + SIZEOF_RBT_CREATE + SIZEOF_RBT_NODE_ADD + sizeof(fts_word_freq_t); @@ -956,7 +965,7 @@ fts_query_add_word_to_document( /*===========================*/ fts_query_t* query, /*!< in: query to update */ doc_id_t doc_id, /*!< in: the document to update */ - const byte* word) /*!< in: the token to add */ + const fts_string_t* word) /*!< in: the token to add */ { ib_rbt_bound_t parent; fts_ranking_t* ranking = NULL; @@ -980,7 +989,7 @@ fts_query_add_word_to_document( } if (ranking != NULL) { - fts_ranking_words_add(query, ranking, (char*)word); + fts_ranking_words_add(query, ranking, word); } } @@ -1010,13 +1019,13 @@ fts_query_check_node( fts_word_freq_t*word_freqs; /* The word must exist. */ - ret = rbt_search(query->word_freqs, &parent, token->f_str); + ret = rbt_search(query->word_freqs, &parent, token); ut_a(ret == 0); word_freqs = rbt_value(fts_word_freq_t, parent.last); query->error = fts_query_filter_doc_ids( - query, token->f_str, word_freqs, node, + query, token, word_freqs, node, node->ilist, ilist_size, TRUE); } } @@ -1073,7 +1082,7 @@ fts_cache_find_wildcard( ret = rbt_search(query->word_freqs, &freq_parent, - srch_text.f_str); + &srch_text); ut_a(ret == 0); @@ -1082,7 +1091,7 @@ fts_cache_find_wildcard( freq_parent.last); query->error = fts_query_filter_doc_ids( - query, srch_text.f_str, + query, &srch_text, word_freqs, node, node->ilist, node->ilist_size, TRUE); @@ -1542,7 +1551,7 @@ fts_merge_doc_ids( for (node = rbt_first(doc_ids); node; node = rbt_next(doc_ids, node)) { fts_ranking_t* ranking; ulint pos = 0; - byte* word = NULL; + fts_string_t word; ranking = rbt_value(fts_ranking_t, node); @@ -1557,7 +1566,7 @@ fts_merge_doc_ids( ut_a(ranking->words); while (fts_ranking_words_get_next(query, ranking, &pos, &word)) { fts_query_add_word_to_document(query, ranking->doc_id, - word); + &word); } } @@ -2472,8 +2481,7 @@ fts_query_search_phrase( token = static_cast( ib_vector_get(tokens, z)); fts_query_add_word_to_document( - query, match->doc_id, - token->f_str); + query, match->doc_id, token); } } } @@ -2562,7 +2570,7 @@ fts_query_phrase_search( && result_str.f_n_char <= fts_max_token_size) { /* Add the word to the RB tree so that we can calculate it's frequencey within a document. */ - fts_query_add_word_freq(query, token->f_str); + fts_query_add_word_freq(query, token); } else { ib_vector_pop(tokens); } @@ -2687,7 +2695,7 @@ fts_query_phrase_search( } fts_query_add_word_to_document( - query, match->doc_id, token->f_str); + query, match->doc_id, token); } query->oper = oper; goto func_exit; @@ -2837,6 +2845,8 @@ fts_query_visitor( ut_ad(query->intersection == NULL); query->intersection = rbt_create( sizeof(fts_ranking_t), fts_ranking_doc_id_cmp); + + query->total_size += SIZEOF_RBT_CREATE; } /* Set the current proximity distance. */ @@ -2858,10 +2868,12 @@ fts_query_visitor( break; case FTS_AST_TERM: + token.f_str = node->term.ptr; + token.f_len = ut_strlen(reinterpret_cast(token.f_str)); /* Add the word to our RB tree that will be used to calculate this terms per document frequency. */ - fts_query_add_word_freq(query, node->term.ptr); + fts_query_add_word_freq(query, &token); ptr = fts_query_get_token(node, &token); query->error = fts_query_execute(query, &token); @@ -2871,6 +2883,10 @@ fts_query_visitor( } break; + case FTS_AST_SUBEXP_LIST: + query->error = fts_ast_visit_sub_exp(node, fts_query_visitor, arg); + break; + default: ut_error; } @@ -2905,13 +2921,7 @@ fts_ast_visit_sub_exp( ut_a(node->type == FTS_AST_SUBEXP_LIST); - node = node->list.head; - - if (!node || !node->next) { - return(error); - } - - cur_oper = node->oper; + cur_oper = query->oper; /* Save current result set */ parent_doc_ids = query->doc_ids; @@ -2927,26 +2937,20 @@ fts_ast_visit_sub_exp( query->multi_exist = false; /* Process nodes in current sub-expression and store its result set in query->doc_ids we created above. */ - error = fts_ast_visit(FTS_NONE, node->next, visitor, + error = fts_ast_visit(FTS_NONE, node, visitor, arg, &will_be_ignored); - /* Reinstate parent node state and prepare for merge. */ + /* Reinstate parent node state */ query->multi_exist = multi_exist; query->oper = cur_oper; - subexpr_doc_ids = query->doc_ids; - - /* Restore current result set. */ - query->doc_ids = parent_doc_ids; /* Merge the sub-expression result with the parent result set. */ + subexpr_doc_ids = query->doc_ids; + query->doc_ids = parent_doc_ids; if (error == DB_SUCCESS && !rbt_empty(subexpr_doc_ids)) { error = fts_merge_doc_ids(query, subexpr_doc_ids); } - if (query->oper == FTS_EXIST) { - query->multi_exist = true; - } - /* Free current result set. Result already merged into parent. */ fts_query_free_doc_ids(query, subexpr_doc_ids); @@ -3033,14 +3037,13 @@ static dberr_t fts_query_filter_doc_ids( /*=====================*/ - fts_query_t* query, /*!< in: query instance */ - const byte* word, /*!< in: the current word */ - fts_word_freq_t*word_freq, /*!< in/out: word frequency */ - const fts_node_t* - node, /*!< in: current FTS node */ - void* data, /*!< in: doc id ilist */ - ulint len, /*!< in: doc id ilist size */ - ibool calc_doc_count) /*!< in: whether to remember doc count */ + fts_query_t* query, /*!< in: query instance */ + const fts_string_t* word, /*!< in: the current word */ + fts_word_freq_t* word_freq, /*!< in/out: word frequency */ + const fts_node_t* node, /*!< in: current FTS node */ + void* data, /*!< in: doc id ilist */ + ulint len, /*!< in: doc id ilist size */ + ibool calc_doc_count) /*!< in: whether to remember doc count */ { byte* ptr = static_cast(data); doc_id_t doc_id = 0; @@ -3163,13 +3166,15 @@ fts_query_read_node( ib_rbt_bound_t parent; fts_word_freq_t* word_freq; ibool skip = FALSE; - byte term[FTS_MAX_WORD_LEN + 1]; + fts_string_t term; + byte buf[FTS_MAX_WORD_LEN + 1]; dberr_t error = DB_SUCCESS; ut_a(query->cur_node->type == FTS_AST_TERM || query->cur_node->type == FTS_AST_TEXT); memset(&node, 0, sizeof(node)); + term.f_str = buf; /* Need to consider the wildcard search case, the word frequency is created on the search string not the actual word. So we need @@ -3179,15 +3184,18 @@ fts_query_read_node( /* These cast are safe since we only care about the terminating NUL character as an end of string marker. */ - ut_strcpy((char*) term, (char*) query->cur_node->term.ptr); + term.f_len = ut_strlen(reinterpret_cast + (query->cur_node->term.ptr)); + ut_ad(FTS_MAX_WORD_LEN >= term.f_len); + memcpy(term.f_str, query->cur_node->term.ptr, term.f_len); } else { - /* Need to copy the NUL character too. */ - memcpy(term, word->f_str, word->f_len); - term[word->f_len] = 0; + term.f_len = word->f_len; + ut_ad(FTS_MAX_WORD_LEN >= word->f_len); + memcpy(term.f_str, word->f_str, word->f_len); } /* Lookup the word in our rb tree, it must exist. */ - ret = rbt_search(query->word_freqs, &parent, term); + ret = rbt_search(query->word_freqs, &parent, &term); ut_a(ret == 0); @@ -3239,7 +3247,7 @@ fts_query_read_node( case 4: /* ILIST */ error = fts_query_filter_doc_ids( - query, word_freq->word, word_freq, + query, &word_freq->word, word_freq, &node, data, len, FALSE); break; @@ -3332,7 +3340,7 @@ fts_query_calculate_idf( if (fts_enable_diag_print) { fprintf(stderr,"'%s' -> " UINT64PF "/" UINT64PF " %6.5lf\n", - word_freq->word, + word_freq->word.f_str, query->total_docs, word_freq->doc_count, word_freq->idf); } @@ -3349,12 +3357,12 @@ fts_query_calculate_ranking( fts_ranking_t* ranking) /*!< in: Document to rank */ { ulint pos = 0; - byte* word = NULL; + fts_string_t word; /* At this stage, ranking->rank should not exceed the 1.0 bound */ ut_ad(ranking->rank <= 1.0 && ranking->rank >= -1.0); - ut_ad(query->word_map->size() == query->word_vector->size()); + ut_ad(rbt_size(query->word_map) == query->word_vector->size()); while (fts_ranking_words_get_next(query, ranking, &pos, &word)) { int ret; @@ -3363,8 +3371,7 @@ fts_query_calculate_ranking( fts_doc_freq_t* doc_freq; fts_word_freq_t* word_freq; - ut_ad(word != NULL); - ret = rbt_search(query->word_freqs, &parent, word); + ret = rbt_search(query->word_freqs, &parent, &word); /* It must exist. */ ut_a(ret == 0); @@ -3620,18 +3627,18 @@ fts_query_free( ut_a(!query->intersection); - if (query->heap) { - mem_heap_free(query->heap); - } - if (query->word_map) { - delete query->word_map; + rbt_free(query->word_map); } if (query->word_vector) { delete query->word_vector; } + if (query->heap) { + mem_heap_free(query->heap); + } + memset(query, 0, sizeof(*query)); } @@ -3820,6 +3827,7 @@ fts_query( query.fts_common_table.type = FTS_COMMON_TABLE; query.fts_common_table.table_id = index->table->id; query.fts_common_table.parent = index->table->name; + query.fts_common_table.table = index->table; charset = fts_index_get_charset(index); @@ -3828,15 +3836,18 @@ fts_query( query.fts_index_table.table_id = index->table->id; query.fts_index_table.parent = index->table->name; query.fts_index_table.charset = charset; + query.fts_index_table.table = index->table; - query.word_map = new word_map_t; + query.word_map = rbt_create_arg_cmp( + sizeof(fts_string_t), innobase_fts_text_cmp, + (void *) charset); query.word_vector = new word_vector_t; query.error = DB_SUCCESS; /* Setup the RB tree that will be used to collect per term statistics. */ query.word_freqs = rbt_create_arg_cmp( - sizeof(fts_word_freq_t), innobase_fts_string_cmp, + sizeof(fts_word_freq_t), innobase_fts_text_cmp, (void*) charset); query.total_size += SIZEOF_RBT_CREATE; @@ -4061,13 +4072,14 @@ fts_print_doc_id( fts_ranking_t* ranking; ranking = rbt_value(fts_ranking_t, node); - fprintf(stderr, "doc_ids info, doc_id: %ld \n", + ib_logf(IB_LOG_LEVEL_INFO, "doc_ids info, doc_id: %ld \n", (ulint) ranking->doc_id); - ulint pos = 0; - byte* value = NULL; - while (fts_ranking_words_get_next(query, ranking, &pos, &value)) { - fprintf(stderr, "doc_ids info, value: %s \n", value); + ulint pos = 0; + fts_string_t word; + + while (fts_ranking_words_get_next(query, ranking, &pos, &word)) { + ib_logf(IB_LOG_LEVEL_INFO, "doc_ids info, value: %s \n", word.f_str); } } } @@ -4123,7 +4135,7 @@ fts_expand_query( fts_ranking_t* ranking; ulint pos; - byte* word; + fts_string_t word; ulint prev_token_size; ulint estimate_size; @@ -4145,22 +4157,17 @@ fts_expand_query( /* Remove words that have already been searched in the first pass */ pos = 0; - word = NULL; while (fts_ranking_words_get_next(query, ranking, &pos, - &word)) { - fts_string_t str; + &word)) { ibool ret; - /* FIXME: We are discarding a const qualifier here. */ - str.f_str = word; - str.f_len = ut_strlen((const char*) str.f_str); - ret = rbt_delete(result_doc.tokens, &str); + ret = rbt_delete(result_doc.tokens, &word); /* The word must exist in the doc we found */ if (!ret) { - fprintf(stderr, " InnoDB: Error: Did not " + ib_logf(IB_LOG_LEVEL_ERROR, "Did not " "find word %s in doc %ld for query " - "expansion search.\n", str.f_str, + "expansion search.\n", word.f_str, (ulint) ranking->doc_id); } } @@ -4185,7 +4192,8 @@ fts_expand_query( fts_token_t* mytoken; mytoken = rbt_value(fts_token_t, token_node); - fts_query_add_word_freq(query, mytoken->text.f_str); + ut_ad(mytoken->text.f_str[mytoken->text.f_len] == 0); + fts_query_add_word_freq(query, &mytoken->text); error = fts_query_union(query, &mytoken->text); if (error != DB_SUCCESS) { @@ -4324,8 +4332,7 @@ fts_phrase_or_proximity_search( token = static_cast( ib_vector_get(tokens, z)); fts_query_add_word_to_document( - query, match[0]->doc_id, - token->f_str); + query, match[0]->doc_id, token); } } } diff --git a/storage/innobase/fts/fts0sql.cc b/storage/innobase/fts/fts0sql.cc index 03c19d93af6..14bc3ec44c9 100644 --- a/storage/innobase/fts/fts0sql.cc +++ b/storage/innobase/fts/fts0sql.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2013, 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 @@ -61,21 +61,28 @@ fts_get_table_id( long */ { int len; + bool hex_name = DICT_TF2_FLAG_IS_SET(fts_table->table, + DICT_TF2_FTS_AUX_HEX_NAME); + + ut_a(fts_table->table != NULL); switch (fts_table->type) { case FTS_COMMON_TABLE: - len = fts_write_object_id(fts_table->table_id, table_id); + len = fts_write_object_id(fts_table->table_id, table_id, + hex_name); break; case FTS_INDEX_TABLE: - len = fts_write_object_id(fts_table->table_id, table_id); + len = fts_write_object_id(fts_table->table_id, table_id, + hex_name); table_id[len] = '_'; ++len; table_id += len; - len += fts_write_object_id(fts_table->index_id, table_id); + len += fts_write_object_id(fts_table->index_id, table_id, + hex_name); break; default: @@ -191,7 +198,7 @@ fts_parse_sql( str = ut_str3cat(fts_sql_begin, str_tmp, fts_sql_end); mem_free(str_tmp); - dict_locked = (fts_table && fts_table->table + dict_locked = (fts_table && fts_table->table->fts && (fts_table->table->fts->fts_status & TABLE_DICT_LOCKED)); diff --git a/storage/innobase/fts/fts0tlex.cc b/storage/innobase/fts/fts0tlex.cc index 717ddb8a77e..f78456d8795 100644 --- a/storage/innobase/fts/fts0tlex.cc +++ b/storage/innobase/fts/fts0tlex.cc @@ -305,9 +305,9 @@ YY_BUFFER_STATE fts0t_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner YY_BUFFER_STATE fts0t_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); YY_BUFFER_STATE fts0t_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); -void *fts0talloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); -void *fts0trealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); -void fts0tfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +void *fts0talloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +void *fts0trealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +void fts0tfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); #define yy_new_buffer fts0t_create_buffer @@ -347,7 +347,7 @@ typedef int yy_state_type; static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); static int yy_get_next_buffer (yyscan_t yyscanner ); -static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. @@ -575,11 +575,11 @@ extern int fts0twrap (yyscan_t yyscanner ); #endif #ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); +static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); +static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); #endif #ifndef YY_NO_INPUT @@ -1601,7 +1601,7 @@ YY_BUFFER_STATE fts0t_scan_bytes (yyconst char * yybytes, int _yybytes_len , y #define YY_EXIT_FAILURE 2 #endif -static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); @@ -1902,7 +1902,7 @@ int fts0tlex_destroy (yyscan_t yyscanner) */ #ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { register int i; for ( i = 0; i < n; ++i ) @@ -1911,7 +1911,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { register int n; for ( n = 0; s[n]; ++n ) @@ -1921,12 +1921,12 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribu } #endif -void *fts0talloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +void *fts0talloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { return (void *) malloc( size ); } -void *fts0trealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +void *fts0trealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those @@ -1938,7 +1938,7 @@ void *fts0trealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __at return (void *) realloc( (char *) ptr, size ); } -void fts0tfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +void fts0tfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { free( (char *) ptr ); /* see fts0trealloc() for (char *) cast */ } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 43befc0dc0c..3fe2e357c6b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -487,6 +487,7 @@ ib_cb_t innodb_api_cb[] = { (ib_cb_t) ib_cursor_open_index_using_name, (ib_cb_t) ib_close_thd, (ib_cb_t) ib_cfg_get_cfg, + (ib_cb_t) ib_cursor_set_memcached_sync, (ib_cb_t) ib_cursor_set_cluster_access, (ib_cb_t) ib_cursor_commit_trx, (ib_cb_t) ib_cfg_trx_level, @@ -759,6 +760,19 @@ innobase_rollback_to_savepoint( be rolled back to savepoint */ void* savepoint); /*!< in: savepoint data */ +/*****************************************************************//** +Check whether innodb state allows to safely release MDL locks after +rollback to savepoint. +@return true if it is safe, false if its not safe. */ +static +bool +innobase_rollback_to_savepoint_can_release_mdl( +/*===========================================*/ + handlerton* hton, /*!< in/out: InnoDB handlerton */ + THD* thd); /*!< in: handle to the MySQL thread of + the user whose XA transaction should + be rolled back to savepoint */ + /*****************************************************************//** Sets a transaction savepoint. @return always 0, that is, always succeeds */ @@ -2841,6 +2855,8 @@ innobase_init( innobase_hton->close_connection = innobase_close_connection; innobase_hton->savepoint_set = innobase_savepoint; innobase_hton->savepoint_rollback = innobase_rollback_to_savepoint; + innobase_hton->savepoint_rollback_can_release_mdl = + innobase_rollback_to_savepoint_can_release_mdl; innobase_hton->savepoint_release = innobase_release_savepoint; innobase_hton->prepare_ordered= NULL; innobase_hton->commit_ordered= innobase_commit_ordered; @@ -4007,6 +4023,38 @@ innobase_rollback_to_savepoint( DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL)); } +/*****************************************************************//** +Check whether innodb state allows to safely release MDL locks after +rollback to savepoint. +When binlog is on, MDL locks acquired after savepoint unit are not +released if there are any locks held in InnoDB. +@return true if it is safe, false if its not safe. */ +static +bool +innobase_rollback_to_savepoint_can_release_mdl( +/*===========================================*/ + handlerton* hton, /*!< in: InnoDB handlerton */ + THD* thd) /*!< in: handle to the MySQL thread + of the user whose transaction should + be rolled back to savepoint */ +{ + trx_t* trx; + + DBUG_ENTER("innobase_rollback_to_savepoint_can_release_mdl"); + DBUG_ASSERT(hton == innodb_hton_ptr); + + trx = check_trx_exists(thd); + ut_ad(trx); + + /* If transaction has not acquired any locks then it is safe + to release MDL after rollback to savepoint */ + if (!(UT_LIST_GET_LEN(trx->lock.trx_locks))) { + DBUG_RETURN(true); + } + + DBUG_RETURN(false); +} + /*****************************************************************//** Release transaction savepoint name. @return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the @@ -5696,23 +5744,7 @@ innobase_fts_text_cmp_prefix( to negate the result */ return(-result); } -/******************************************************************//** -compare two character string according to their charset. */ -UNIV_INTERN -int -innobase_fts_string_cmp( -/*====================*/ - const void* cs, /*!< in: Character set */ - const void* p1, /*!< in: key */ - const void* p2) /*!< in: node */ -{ - const CHARSET_INFO* charset = (const CHARSET_INFO*) cs; - uchar* s1 = (uchar*) p1; - uchar* s2 = *(uchar**) p2; - return(ha_compare_text(charset, s1, strlen((const char*) s1), - s2, strlen((const char*) s2), 0, 0)); -} /******************************************************************//** Makes all characters in a string lower case. */ UNIV_INTERN @@ -8718,12 +8750,6 @@ ha_innobase::position( } } -/* limit innodb monitor access to users with PROCESS privilege. -See http://bugs.mysql.com/32710 for expl. why we choose PROCESS. */ -#define IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name, thd) \ - (row_is_magic_monitor_table(table_name) \ - && check_global_access(thd, PROCESS_ACL)) - /*****************************************************************//** Check whether there exist a column named as "FTS_DOC_ID", which is reserved for InnoDB FTS Doc ID @@ -8838,16 +8864,6 @@ create_table_def( DBUG_RETURN(ER_TABLE_NAME); } - /* table_name must contain '/'. Later in the code we assert if it - does not */ - if (strcmp(strchr(table_name, '/') + 1, - "innodb_table_monitor") == 0) { - push_warning( - thd, Sql_condition::WARN_LEVEL_WARN, - HA_ERR_WRONG_COMMAND, - DEPRECATED_MSG_INNODB_TABLE_MONITOR); - } - n_cols = form->s->fields; /* Check whether there already exists a FTS_DOC_ID column */ @@ -9767,6 +9783,11 @@ index_bad: *flags2 |= DICT_TF2_USE_TABLESPACE; } + /* Set the flags2 when create table or alter tables */ + *flags2 |= DICT_TF2_FTS_AUX_HEX_NAME; + DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name", + *flags2 &= ~DICT_TF2_FTS_AUX_HEX_NAME;); + DBUG_RETURN(true); } @@ -9858,8 +9879,23 @@ ha_innobase::create( DBUG_RETURN(-1); } - if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) { - DBUG_RETURN(HA_ERR_GENERIC); + if (row_is_magic_monitor_table(norm_name)) { + push_warning_printf(thd, + Sql_condition::WARN_LEVEL_WARN, + HA_ERR_WRONG_COMMAND, + "Using the table name %s to enable " + "diagnostic output is deprecated " + "and may be removed in future releases. " + "Use INFORMATION_SCHEMA or " + "PERFORMANCE_SCHEMA tables or " + "SET GLOBAL innodb_status_output=ON.", + dict_remove_db_name(norm_name)); + + /* Limit innodb monitor access to users with PROCESS privilege. + See http://bugs.mysql.com/32710 why we chose PROCESS. */ + if (check_global_access(thd, PROCESS_ACL)) { + DBUG_RETURN(HA_ERR_GENERIC); + } } /* Get the transaction associated with the current thd, or create one @@ -10303,7 +10339,8 @@ ha_innobase::delete_table( if (srv_read_only_mode) { DBUG_RETURN(HA_ERR_TABLE_READONLY); - } else if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) { + } else if (row_is_magic_monitor_table(norm_name) + && check_global_access(thd, PROCESS_ACL)) { DBUG_RETURN(HA_ERR_GENERIC); } @@ -10539,17 +10576,7 @@ innobase_rename_table( } } - if (error != DB_SUCCESS) { - if (!srv_read_only_mode) { - FILE* ef = dict_foreign_err_file; - - fputs("InnoDB: Renaming table ", ef); - ut_print_name(ef, trx, TRUE, norm_from); - fputs(" to ", ef); - ut_print_name(ef, trx, TRUE, norm_to); - fputs(" failed!\n", ef); - } - } else { + if (error == DB_SUCCESS) { #ifndef __WIN__ sql_print_warning("Rename partition table %s " "succeeds after converting to lower " @@ -11532,7 +11559,8 @@ ha_innobase::optimize( calls to OPTIMIZE, which is undesirable. */ if (innodb_optimize_fulltext_only) { - if (prebuilt->table->fts && prebuilt->table->fts->cache) { + if (prebuilt->table->fts && prebuilt->table->fts->cache + && !dict_table_is_discarded(prebuilt->table)) { fts_sync_table(prebuilt->table); fts_optimize_table(prebuilt->table); } @@ -15568,6 +15596,7 @@ innobase_fts_find_ranking( static my_bool innodb_purge_run_now = TRUE; static my_bool innodb_purge_stop_now = TRUE; static my_bool innodb_log_checkpoint_now = TRUE; +static my_bool innodb_buf_flush_list_now = TRUE; /****************************************************************//** Set the purge state to RUN. If purge is disabled then it @@ -15641,6 +15670,29 @@ checkpoint_now_set( fil_flush_file_spaces(FIL_TABLESPACE); } } + +/****************************************************************//** +Force a dirty pages flush now. */ +static +void +buf_flush_list_now_set( +/*===================*/ + THD* thd /*!< in: thread handle */ + __attribute__((unused)), + struct st_mysql_sys_var* var /*!< in: pointer to system + variable */ + __attribute__((unused)), + void* var_ptr /*!< out: where the formal + string goes */ + __attribute__((unused)), + const void* save) /*!< in: immediate result from + check function */ +{ + if (*(my_bool*) save) { + buf_flush_list(ULINT_MAX, LSN_MAX, NULL); + buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); + } +} #endif /* UNIV_DEBUG */ /*********************************************************************** @@ -15790,6 +15842,26 @@ buffer_pool_load_abort( } } +/** Update innodb_status_output or innodb_status_output_locks, +which control InnoDB "status monitor" output to the error log. +@param[in] thd thread handle +@param[in] var system variable +@param[out] var_ptr current value +@param[in] save to-be-assigned value */ +static +void +innodb_status_output_update( + THD* thd __attribute__((unused)), + struct st_mysql_sys_var* var __attribute__((unused)), + void* var_ptr __attribute__((unused)), + const void* save __attribute__((unused))) +{ + *static_cast(var_ptr) = *static_cast(save); + /* The lock timeout monitor thread also takes care of this + output. */ + os_event_set(lock_sys->timeout_event); +} + static SHOW_VAR innodb_status_variables_export[]= { {"Innodb", (char*) &show_innodb_vars, SHOW_FUNC}, {NullS, NullS, SHOW_LONG} @@ -15884,6 +15956,11 @@ static MYSQL_SYSVAR_BOOL(log_checkpoint_now, innodb_log_checkpoint_now, PLUGIN_VAR_OPCMDARG, "Force checkpoint now", NULL, checkpoint_now_set, FALSE); + +static MYSQL_SYSVAR_BOOL(buf_flush_list_now, innodb_buf_flush_list_now, + PLUGIN_VAR_OPCMDARG, + "Force dirty page flush now", + NULL, buf_flush_list_now_set, FALSE); #endif /* UNIV_DEBUG */ static MYSQL_SYSVAR_ULONG(purge_batch_size, srv_purge_batch_size, @@ -16560,6 +16637,15 @@ static MYSQL_SYSVAR_STR(monitor_reset_all, innobase_reset_all_monitor_counter, innodb_monitor_validate, innodb_reset_all_monitor_update, NULL); +static MYSQL_SYSVAR_BOOL(status_output, srv_print_innodb_monitor, + PLUGIN_VAR_OPCMDARG, "Enable InnoDB monitor output to the error log.", + NULL, innodb_status_output_update, FALSE); + +static MYSQL_SYSVAR_BOOL(status_output_locks, srv_print_innodb_lock_monitor, + PLUGIN_VAR_OPCMDARG, "Enable InnoDB lock monitor output to the error log." + " Requires innodb_status_output=ON.", + NULL, innodb_status_output_update, FALSE); + static MYSQL_SYSVAR_BOOL(print_all_deadlocks, srv_print_all_deadlocks, PLUGIN_VAR_OPCMDARG, "Print all deadlocks to MySQL error log (off by default)", @@ -16747,11 +16833,14 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(purge_run_now), MYSQL_SYSVAR(purge_stop_now), MYSQL_SYSVAR(log_checkpoint_now), + MYSQL_SYSVAR(buf_flush_list_now), #endif /* UNIV_DEBUG */ #if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG MYSQL_SYSVAR(page_hash_locks), MYSQL_SYSVAR(doublewrite_batch_size), #endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */ + MYSQL_SYSVAR(status_output), + MYSQL_SYSVAR(status_output_locks), MYSQL_SYSVAR(print_all_deadlocks), MYSQL_SYSVAR(cmp_per_index_enabled), MYSQL_SYSVAR(undo_logs), diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index d7e16d93c6a..191050bdce2 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -46,7 +46,7 @@ Smart ALTER TABLE #include "srv0mon.h" #include "fts0priv.h" #include "pars0pars.h" - +#include "row0sel.h" #include "ha_innodb.h" /** Operations for creating secondary indexes (no rebuild needed) */ @@ -240,6 +240,7 @@ ha_innobase::check_if_supported_inplace_alter( innobase_get_err_msg(ER_READ_ONLY_MODE); DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } else if (srv_created_new_raw || srv_force_recovery) { + ha_alter_info->unsupported_reason = innobase_get_err_msg(ER_READ_ONLY_MODE); DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); @@ -2531,15 +2532,16 @@ innobase_drop_fts_index_table( /** Get the new column names if any columns were renamed @param ha_alter_info Data used during in-place alter @param altered_table MySQL table that is being altered +@param table MySQL table as it is before the ALTER operation @param user_table InnoDB table as it is before the ALTER operation @param heap Memory heap for the allocation @return array of new column names in rebuilt_table, or NULL if not renamed */ static __attribute__((nonnull, warn_unused_result)) const char** innobase_get_col_names( -/*===================*/ Alter_inplace_info* ha_alter_info, const TABLE* altered_table, + const TABLE* table, const dict_table_t* user_table, mem_heap_t* heap) { @@ -2547,19 +2549,31 @@ innobase_get_col_names( uint i; DBUG_ENTER("innobase_get_col_names"); - DBUG_ASSERT(user_table->n_def > altered_table->s->fields); + DBUG_ASSERT(user_table->n_def > table->s->fields); DBUG_ASSERT(ha_alter_info->handler_flags & Alter_inplace_info::ALTER_COLUMN_NAME); cols = static_cast( - mem_heap_alloc(heap, user_table->n_def * sizeof *cols)); + mem_heap_zalloc(heap, user_table->n_def * sizeof *cols)); - for (i = 0; i < altered_table->s->fields; i++) { - const Field* field = altered_table->field[i]; - cols[i] = field->field_name; + i = 0; + List_iterator_fast cf_it( + ha_alter_info->alter_info->create_list); + while (const Create_field* new_field = cf_it++) { + DBUG_ASSERT(i < altered_table->s->fields); + + for (uint old_i = 0; table->field[old_i]; old_i++) { + if (new_field->field == table->field[old_i]) { + cols[old_i] = new_field->field_name; + break; + } + } + + i++; } /* Copy the internal column names. */ + i = table->s->fields; cols[i] = dict_table_get_col_name(user_table, i); while (++i < user_table->n_def) { @@ -3337,6 +3351,9 @@ ha_innobase::prepare_inplace_alter_table( ulint fts_doc_col_no = ULINT_UNDEFINED; bool add_fts_doc_id = false; bool add_fts_doc_id_idx = false; +#ifdef _WIN32 + bool add_fts_idx = false; +#endif /* _WIN32 */ DBUG_ENTER("prepare_inplace_alter_table"); DBUG_ASSERT(!ha_alter_info->handler_ctx); @@ -3481,6 +3498,9 @@ check_if_ok_to_rename: & ~(HA_FULLTEXT | HA_PACK_KEY | HA_BINARY_PACK_KEY))); +#ifdef _WIN32 + add_fts_idx = true; +#endif /* _WIN32 */ continue; } @@ -3491,6 +3511,20 @@ check_if_ok_to_rename: } } +#ifdef _WIN32 + /* We won't be allowed to add fts index to a table with + fts indexes already but without AUX_HEX_NAME set. + This means the aux tables of the table failed to + rename to hex format but new created aux tables + shall be in hex format, which is contradictory. + It's only for Windows. */ + if (!DICT_TF2_FLAG_IS_SET(indexed_table, DICT_TF2_FTS_AUX_HEX_NAME) + && indexed_table->fts != NULL && add_fts_idx) { + my_error(ER_INNODB_FT_AUX_NOT_HEX_ID, MYF(0)); + goto err_exit_no_heap; + } +#endif /* _WIN32 */ + /* Check existing index definitions for too-long column prefixes as well, in case max_col_len shrunk. */ for (const dict_index_t* index @@ -3524,8 +3558,8 @@ check_if_ok_to_rename: if (ha_alter_info->handler_flags & Alter_inplace_info::ALTER_COLUMN_NAME) { col_names = innobase_get_col_names( - ha_alter_info, altered_table, indexed_table, - heap); + ha_alter_info, altered_table, table, + indexed_table, heap); } else { col_names = NULL; } @@ -4595,16 +4629,39 @@ commit_get_autoinc( & Alter_inplace_info::CHANGE_CREATE_OPTION) && (ha_alter_info->create_info->used_fields & HA_CREATE_USED_AUTO)) { - /* An AUTO_INCREMENT value was supplied, but the table - was not rebuilt. Get the user-supplied value or the - last value from the sequence. */ - ut_ad(old_table->found_next_number_field); + /* An AUTO_INCREMENT value was supplied, but the table was not + rebuilt. Get the user-supplied value or the last value from the + sequence. */ + ib_uint64_t max_value_table; + dberr_t err; + + Field* autoinc_field = + old_table->found_next_number_field; + + dict_index_t* index = dict_table_get_index_on_first_col( + ctx->old_table, autoinc_field->field_index); max_autoinc = ha_alter_info->create_info->auto_increment_value; dict_table_autoinc_lock(ctx->old_table); - if (max_autoinc < ctx->old_table->autoinc) { - max_autoinc = ctx->old_table->autoinc; + + err = row_search_max_autoinc( + index, autoinc_field->field_name, &max_value_table); + + if (err != DB_SUCCESS) { + ut_ad(0); + max_autoinc = 0; + } else if (max_autoinc <= max_value_table) { + ulonglong col_max_value; + ulonglong offset; + + col_max_value = innobase_get_int_col_max_value( + old_table->found_next_number_field); + + offset = ctx->prebuilt->autoinc_offset; + max_autoinc = innobase_next_autoinc( + max_value_table, 1, 1, offset, + col_max_value); } dict_table_autoinc_unlock(ctx->old_table); } else { diff --git a/storage/innobase/include/api0api.h b/storage/innobase/include/api0api.h index c294e3f34d5..d77d691becc 100644 --- a/storage/innobase/include/api0api.h +++ b/storage/innobase/include/api0api.h @@ -1256,6 +1256,16 @@ int ib_cfg_get_cfg(); /*============*/ +/*****************************************************************//** +Increase/decrease the memcached sync count of table to sync memcached +DML with SQL DDLs. +@return DB_SUCCESS or error number */ +ib_err_t +ib_cursor_set_memcached_sync( +/*=========================*/ + ib_crsr_t ib_crsr, /*!< in: cursor */ + ib_bool_t flag); /*!< in: true for increasing */ + /*****************************************************************//** Check whether the table name conforms to our requirements. Currently we only do a simple check for the presence of a '/'. diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h index fc008cdd185..cfbaacf4de3 100644 --- a/storage/innobase/include/btr0pcur.h +++ b/storage/innobase/include/btr0pcur.h @@ -459,6 +459,13 @@ void btr_pcur_move_to_prev_on_page( /*==========================*/ btr_pcur_t* cursor);/*!< in/out: persistent cursor */ +/*********************************************************//** +Moves the persistent cursor to the infimum record on the same page. */ +UNIV_INLINE +void +btr_pcur_move_before_first_on_page( +/*===============================*/ + btr_pcur_t* cursor); /*!< in/out: persistent cursor */ /** Position state of persistent B-tree cursor. */ enum pcur_pos_t { diff --git a/storage/innobase/include/btr0pcur.ic b/storage/innobase/include/btr0pcur.ic index 29f2fc722a2..7e355d3709d 100644 --- a/storage/innobase/include/btr0pcur.ic +++ b/storage/innobase/include/btr0pcur.ic @@ -588,3 +588,19 @@ btr_pcur_close( cursor->trx_if_known = NULL; } + +/*********************************************************//** +Moves the persistent cursor to the infimum record on the same page. */ +UNIV_INLINE +void +btr_pcur_move_before_first_on_page( +/*===============================*/ + btr_pcur_t* cursor) /*!< in/out: persistent cursor */ +{ + ut_ad(cursor->latch_mode != BTR_NO_LATCHES); + + page_cur_set_before_first(btr_pcur_get_block(cursor), + btr_pcur_get_page_cur(cursor)); + + cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; +} diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 7ad6339e63b..7e590c05209 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -607,6 +607,23 @@ buf_block_buf_fix_inc_func( # endif /* UNIV_SYNC_DEBUG */ buf_block_t* block) /*!< in/out: block to bufferfix */ __attribute__((nonnull)); + +/*******************************************************************//** +Increments the bufferfix count. */ +UNIV_INLINE +void +buf_block_fix( +/*===========*/ + buf_block_t* block); /*!< in/out: block to bufferfix */ + +/*******************************************************************//** +Increments the bufferfix count. */ +UNIV_INLINE +void +buf_block_unfix( +/*===========*/ + buf_block_t* block); /*!< in/out: block to bufferfix */ + # ifdef UNIV_SYNC_DEBUG /** Increments the bufferfix count. @param b in/out: block to bufferfix @@ -1423,38 +1440,42 @@ struct buf_page_t{ by buf_pool->mutex. */ /* @{ */ - unsigned space:32; /*!< tablespace id; also protected + ib_uint32_t space; /*!< tablespace id; also protected by buf_pool->mutex. */ - unsigned offset:32; /*!< page number; also protected + ib_uint32_t offset; /*!< page number; also protected by buf_pool->mutex. */ + /** count of how manyfold this block is currently bufferfixed */ +#ifdef PAGE_ATOMIC_REF_COUNT + ib_uint32_t buf_fix_count; + /** type of pending I/O operation; also protected by + buf_pool->mutex for writes only @see enum buf_io_fix */ + byte io_fix; + + byte state; +#else + unsigned buf_fix_count:19; + + /** type of pending I/O operation; also protected by + buf_pool->mutex for writes only @see enum buf_io_fix */ + unsigned io_fix:2; + + /*!< state of the control block; also protected by buf_pool->mutex. + State transitions from BUF_BLOCK_READY_FOR_USE to BUF_BLOCK_MEMORY + need not be protected by buf_page_get_mutex(). @see enum buf_page_state. + State changes that are relevant to page_hash are additionally protected + by the appropriate page_hash mutex i.e.: if a page is in page_hash or + is being added to/removed from page_hash then the corresponding changes + must also be protected by page_hash mutex. */ unsigned state:BUF_PAGE_STATE_BITS; - /*!< state of the control block; also - protected by buf_pool->mutex. - State transitions from - BUF_BLOCK_READY_FOR_USE to - BUF_BLOCK_MEMORY need not be - protected by buf_page_get_mutex(). - @see enum buf_page_state. - State changes that are relevant - to page_hash are additionally - protected by the appropriate - page_hash mutex i.e.: if a page - is in page_hash or is being - added to/removed from page_hash - then the corresponding changes - must also be protected by - page_hash mutex. */ + +#endif /* PAGE_ATOMIC_REF_COUNT */ + #ifndef UNIV_HOTBACKUP unsigned flush_type:2; /*!< if this block is currently being flushed to disk, this tells the flush_type. @see buf_flush_t */ - unsigned io_fix:2; /*!< type of pending I/O operation; - also protected by buf_pool->mutex - @see enum buf_io_fix */ - unsigned buf_fix_count:19;/*!< count of how manyfold this block - is currently bufferfixed */ unsigned buf_pool_index:6;/*!< index number of the buffer pool that this block belongs to */ # if MAX_BUFFER_POOLS > 64 @@ -1608,7 +1629,7 @@ struct buf_block_t{ decompressed LRU list; used in debugging */ #endif /* UNIV_DEBUG */ - ib_mutex_t mutex; /*!< mutex protecting this block: + ib_mutex_t mutex; /*!< mutex protecting this block: state (also protected by the buffer pool mutex), io_fix, buf_fix_count, and accessed; we introduce this new @@ -1794,9 +1815,9 @@ struct buf_pool_t{ /** @name General fields */ /* @{ */ - ib_mutex_t mutex; /*!< Buffer pool mutex of this + ib_mutex_t mutex; /*!< Buffer pool mutex of this instance */ - ib_mutex_t zip_mutex; /*!< Zip mutex of this buffer + ib_mutex_t zip_mutex; /*!< Zip mutex of this buffer pool instance, protects compressed only pages (of type buf_page_t, not buf_block_t */ @@ -1850,7 +1871,7 @@ struct buf_pool_t{ /* @{ */ - ib_mutex_t flush_list_mutex;/*!< mutex protecting the + ib_mutex_t flush_list_mutex;/*!< mutex protecting the flush list access. This mutex protects flush_list, flush_rbt and bpage::list pointers when @@ -1968,27 +1989,39 @@ Use these instead of accessing buf_pool->mutex directly. */ /** Test if a buffer pool mutex is owned. */ #define buf_pool_mutex_own(b) mutex_own(&b->mutex) /** Acquire a buffer pool mutex. */ -#define buf_pool_mutex_enter(b) do { \ - ut_ad(!mutex_own(&b->zip_mutex)); \ - mutex_enter(&b->mutex); \ +#define buf_pool_mutex_enter(b) do { \ + ut_ad(!mutex_own(&b->zip_mutex)); \ + mutex_enter(&b->mutex); \ } while (0) /** Test if flush list mutex is owned. */ #define buf_flush_list_mutex_own(b) mutex_own(&b->flush_list_mutex) /** Acquire the flush list mutex. */ -#define buf_flush_list_mutex_enter(b) do { \ - mutex_enter(&b->flush_list_mutex); \ +#define buf_flush_list_mutex_enter(b) do { \ + mutex_enter(&b->flush_list_mutex); \ } while (0) /** Release the flush list mutex. */ -# define buf_flush_list_mutex_exit(b) do { \ - mutex_exit(&b->flush_list_mutex); \ +# define buf_flush_list_mutex_exit(b) do { \ + mutex_exit(&b->flush_list_mutex); \ } while (0) +/** Test if block->mutex is owned. */ +#define buf_block_mutex_own(b) mutex_own(&(b)->mutex) + +/** Acquire the block->mutex. */ +#define buf_block_mutex_enter(b) do { \ + mutex_enter(&(b)->mutex); \ +} while (0) + +/** Release the trx->mutex. */ +#define buf_block_mutex_exit(b) do { \ + mutex_exit(&(b)->mutex); \ +} while (0) /** Get appropriate page_hash_lock. */ -# define buf_page_hash_lock_get(b, f) \ +# define buf_page_hash_lock_get(b, f) \ hash_get_lock(b->page_hash, f) #ifdef UNIV_SYNC_DEBUG diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic index 08b31a59da3..85868ad9f0e 100644 --- a/storage/innobase/include/buf0buf.ic +++ b/storage/innobase/include/buf0buf.ic @@ -342,15 +342,16 @@ buf_page_get_mutex( /*===============*/ const buf_page_t* bpage) /*!< in: pointer to control block */ { - buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); - switch (buf_page_get_state(bpage)) { case BUF_BLOCK_POOL_WATCH: ut_error; return(NULL); case BUF_BLOCK_ZIP_PAGE: - case BUF_BLOCK_ZIP_DIRTY: + case BUF_BLOCK_ZIP_DIRTY: { + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + return(&buf_pool->zip_mutex); + } default: return(&((buf_block_t*) bpage)->mutex); } @@ -620,10 +621,11 @@ buf_page_set_accessed( buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); ut_ad(!buf_pool_mutex_own(buf_pool)); ut_ad(mutex_own(buf_page_get_mutex(bpage))); -#endif +#endif /* UNIV_DEBUG */ + ut_a(buf_page_in_file(bpage)); - if (!bpage->access_time) { + if (bpage->access_time == 0) { /* Make this the time of the first access. */ bpage->access_time = ut_time_ms(); } @@ -996,6 +998,25 @@ buf_block_get_modify_clock( return(block->modify_clock); } +/*******************************************************************//** +Increments the bufferfix count. */ +UNIV_INLINE +void +buf_block_fix( +/*===========*/ + buf_block_t* block) /*!< in/out: block to bufferfix */ +{ +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_increment_uint32(&block->page.buf_fix_count, 1); +#else + ib_mutex_t* block_mutex = buf_page_get_mutex(&block->page); + + mutex_enter(block_mutex); + ++block->page.buf_fix_count; + mutex_exit(block_mutex); +#endif /* PAGE_ATOMIC_REF_COUNT */ +} + /*******************************************************************//** Increments the bufferfix count. */ UNIV_INLINE @@ -1014,9 +1035,35 @@ buf_block_buf_fix_inc_func( ret = rw_lock_s_lock_nowait(&(block->debug_latch), file, line); ut_a(ret); #endif /* UNIV_SYNC_DEBUG */ + +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_increment_uint32(&block->page.buf_fix_count, 1); +#else ut_ad(mutex_own(&block->mutex)); - block->page.buf_fix_count++; + ++block->page.buf_fix_count; +#endif /* PAGE_ATOMIC_REF_COUNT */ +} + +/*******************************************************************//** +Decrements the bufferfix count. */ +UNIV_INLINE +void +buf_block_unfix( +/*============*/ + buf_block_t* block) /*!< in/out: block to bufferunfix */ +{ + ut_ad(block->page.buf_fix_count > 0); + +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_decrement_uint32(&block->page.buf_fix_count, 1); +#else + ib_mutex_t* block_mutex = buf_page_get_mutex(&block->page); + + mutex_enter(block_mutex); + --block->page.buf_fix_count; + mutex_exit(block_mutex); +#endif /* PAGE_ATOMIC_REF_COUNT */ } /*******************************************************************//** @@ -1027,9 +1074,16 @@ buf_block_buf_fix_dec( /*==================*/ buf_block_t* block) /*!< in/out: block to bufferunfix */ { - ut_ad(mutex_own(&block->mutex)); + ut_ad(block->page.buf_fix_count > 0); + +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_decrement_uint32(&block->page.buf_fix_count, 1); +#else + mutex_enter(&block->mutex); + --block->page.buf_fix_count; + mutex_exit(&block->mutex); +#endif /* PAGE_ATOMIC_REF_COUNT */ - block->page.buf_fix_count--; #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&block->debug_latch); #endif @@ -1288,27 +1342,20 @@ buf_page_release_zip( buf_page_t* bpage) /*!< in: buffer block */ { buf_block_t* block; - buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); - ut_ad(bpage); - ut_a(bpage->buf_fix_count > 0); + block = (buf_block_t*) bpage; switch (buf_page_get_state(bpage)) { - case BUF_BLOCK_ZIP_PAGE: - case BUF_BLOCK_ZIP_DIRTY: - mutex_enter(&buf_pool->zip_mutex); - bpage->buf_fix_count--; - mutex_exit(&buf_pool->zip_mutex); - return; case BUF_BLOCK_FILE_PAGE: - block = (buf_block_t*) bpage; - mutex_enter(&block->mutex); #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&block->debug_latch); -#endif - bpage->buf_fix_count--; - mutex_exit(&block->mutex); +#endif /* UNUV_SYNC_DEBUG */ + /* Fall through */ + case BUF_BLOCK_ZIP_PAGE: + case BUF_BLOCK_ZIP_DIRTY: + buf_block_unfix(block); return; + case BUF_BLOCK_POOL_WATCH: case BUF_BLOCK_NOT_USED: case BUF_BLOCK_READY_FOR_USE: @@ -1331,25 +1378,18 @@ buf_page_release( ulint rw_latch) /*!< in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ { - ut_ad(block); - ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); - ut_a(block->page.buf_fix_count > 0); - - mutex_enter(&block->mutex); #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&(block->debug_latch)); #endif - block->page.buf_fix_count--; - - mutex_exit(&block->mutex); - if (rw_latch == RW_S_LATCH) { rw_lock_s_unlock(&(block->lock)); } else if (rw_latch == RW_X_LATCH) { rw_lock_x_unlock(&(block->lock)); } + + buf_block_unfix(block); } #ifdef UNIV_SYNC_DEBUG @@ -1367,6 +1407,7 @@ buf_block_dbg_add_level( { sync_thread_add_level(&block->lock, level, FALSE); } + #endif /* UNIV_SYNC_DEBUG */ /********************************************************************//** Acquire mutex on all buffer pool instances. */ diff --git a/storage/innobase/include/buf0dblwr.h b/storage/innobase/include/buf0dblwr.h index 1b9336f4002..740286d0a82 100644 --- a/storage/innobase/include/buf0dblwr.h +++ b/storage/innobase/include/buf0dblwr.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2013, 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 @@ -29,6 +29,7 @@ Created 2011/12/19 Inaam Rana #include "univ.i" #include "ut0byte.h" #include "log0log.h" +#include "log0recv.h" #ifndef UNIV_HOTBACKUP @@ -44,18 +45,25 @@ UNIV_INTERN void buf_dblwr_create(void); /*==================*/ + /****************************************************************//** At a database startup initializes the doublewrite buffer memory structure if we already have a doublewrite buffer created in the data files. If we are upgrading to an InnoDB version which supports multiple tablespaces, then this function performs the necessary update operations. If we are in a crash -recovery, this function uses a possible doublewrite buffer to restore -half-written pages in the data files. */ +recovery, this function loads the pages from double write buffer into memory. */ UNIV_INTERN void -buf_dblwr_init_or_restore_pages( -/*============================*/ - ibool restore_corrupt_pages); /*!< in: TRUE=restore pages */ +buf_dblwr_init_or_load_pages( +/*=========================*/ + bool load_corrupt_pages); + +/****************************************************************//** +Process the double write buffer pages. */ +void +buf_dblwr_process(void); +/*===================*/ + /****************************************************************//** frees doublewrite buffer. */ UNIV_INTERN diff --git a/storage/innobase/include/buf0flu.h b/storage/innobase/include/buf0flu.h index 6fee9afcc91..f116720574b 100644 --- a/storage/innobase/include/buf0flu.h +++ b/storage/innobase/include/buf0flu.h @@ -234,16 +234,16 @@ NOTE: in simulated aio we must call os_aio_simulated_wake_handler_threads after we have posted a batch of writes! NOTE: buf_pool->mutex and buf_page_get_mutex(bpage) must be held upon entering this function, and they will be released by this -function. */ +function if it returns true. +@return TRUE if the page was flushed */ UNIV_INTERN -void +bool buf_flush_page( /*===========*/ buf_pool_t* buf_pool, /*!< in: buffer pool instance */ buf_page_t* bpage, /*!< in: buffer control block */ buf_flush_t flush_type, /*!< in: type of flush */ - bool sync) /*!< in: true if sync IO request */ - __attribute__((nonnull)); + bool sync); /*!< in: true if sync IO request */ /********************************************************************//** Returns true if the block is modified and ready for flushing. @return true if can flush immediately */ diff --git a/storage/innobase/include/buf0types.h b/storage/innobase/include/buf0types.h index 307ef18f0c2..11bbc9b5c8a 100644 --- a/storage/innobase/include/buf0types.h +++ b/storage/innobase/include/buf0types.h @@ -26,6 +26,10 @@ Created 11/17/1995 Heikki Tuuri #ifndef buf0types_h #define buf0types_h +#if defined(INNODB_PAGE_ATOMIC_REF_COUNT) && defined(HAVE_ATOMIC_BUILTINS) +#define PAGE_ATOMIC_REF_COUNT +#endif /* INNODB_PAGE_ATOMIC_REF_COUNT && HAVE_ATOMIC_BUILTINS */ + /** Buffer page (uncompressed or compressed) */ struct buf_page_t; /** Buffer block for which an uncompressed page exists */ diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index f740c427006..ce709a2e912 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -1443,20 +1443,16 @@ UNIV_INTERN void dict_table_stats_lock( /*==================*/ - const dict_table_t* table, /*!< in: table */ - ulint latch_mode) /*!< in: RW_S_LATCH or - RW_X_LATCH */ - __attribute__((nonnull)); + dict_table_t* table, /*!< in: table */ + ulint latch_mode); /*!< in: RW_S_LATCH or RW_X_LATCH */ /**********************************************************************//** Unlock the latch that has been locked by dict_table_stats_lock() */ UNIV_INTERN void dict_table_stats_unlock( /*====================*/ - const dict_table_t* table, /*!< in: table */ - ulint latch_mode) /*!< in: RW_S_LATCH or - RW_X_LATCH */ - __attribute__((nonnull)); + dict_table_t* table, /*!< in: table */ + ulint latch_mode); /*!< in: RW_S_LATCH or RW_X_LATCH */ /********************************************************************//** Checks if the database name in two table names is the same. @return TRUE if same db name */ @@ -1802,6 +1798,17 @@ const char* dict_tf_to_row_format_string( /*=========================*/ ulint table_flag); /*!< in: row format setting */ +/*****************************************************************//** +Get index by first field of the index +@return index which is having first field matches +with the field present in field_index position of table */ +UNIV_INLINE +dict_index_t* +dict_table_get_index_on_first_col( +/*==============================*/ + const dict_table_t* table, /*!< in: table */ + ulint col_index); /*!< in: position of column + in table */ #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index 83953c9325a..066ffe47e4a 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -1403,4 +1403,31 @@ dict_table_is_temporary( return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY)); } +/**********************************************************************//** +Get index by first field of the index +@return index which is having first field matches +with the field present in field_index position of table */ +UNIV_INLINE +dict_index_t* +dict_table_get_index_on_first_col( +/*==============================*/ + const dict_table_t* table, /*!< in: table */ + ulint col_index) /*!< in: position of column + in table */ +{ + ut_ad(col_index < table->n_cols); + + dict_col_t* column = dict_table_get_nth_col(table, col_index); + + for (dict_index_t* index = dict_table_get_first_index(table); + index != NULL; index = dict_table_get_next_index(index)) { + + if (index->fields[0].col == column) { + return(index); + } + } + ut_error; + return(0); +} + #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index bc90e2ddfaf..eb259020106 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -191,7 +191,7 @@ ROW_FORMAT=REDUNDANT. InnoDB engines do not check these flags for unknown bits in order to protect backward incompatibility. */ /* @{ */ /** Total number of bits in table->flags2. */ -#define DICT_TF2_BITS 6 +#define DICT_TF2_BITS 7 #define DICT_TF2_BIT_MASK ~(~0 << DICT_TF2_BITS) /** TEMPORARY; TRUE for tables from CREATE TEMPORARY TABLE. */ @@ -209,6 +209,10 @@ use its own tablespace instead of the system tablespace. */ /** Set when we discard/detach the tablespace */ #define DICT_TF2_DISCARDED 32 + +/** This bit is set if all aux table names (both common tables and +index tables) of a FTS table are in HEX format. */ +#define DICT_TF2_FTS_AUX_HEX_NAME 64 /* @} */ #define DICT_TF2_FLAG_SET(table, flag) \ @@ -717,6 +721,11 @@ a foreign key constraint is enforced, therefore RESTRICT just means no flag */ #define DICT_FOREIGN_ON_UPDATE_NO_ACTION 32 /*!< ON UPDATE NO ACTION */ /* @} */ +/* This flag is for sync SQL DDL and memcached DML. +if table->memcached_sync_count == DICT_TABLE_IN_DDL means there's DDL running on +the table, DML from memcached will be blocked. */ +#define DICT_TABLE_IN_DDL -1 + /** Data structure for a database table. Most fields will be initialized to 0, NULL or FALSE in dict_mem_table_create(). */ struct dict_table_t{ @@ -830,9 +839,28 @@ struct dict_table_t{ initialized in dict_table_add_to_cache() */ /** Statistics for query optimization */ /* @{ */ + rw_lock_t* stats_latch; /*!< this latch protects: + dict_table_t::stat_initialized + dict_table_t::stat_n_rows (*) + dict_table_t::stat_clustered_index_size + dict_table_t::stat_sum_of_other_index_sizes + dict_table_t::stat_modified_counter (*) + dict_table_t::indexes*::stat_n_diff_key_vals[] + dict_table_t::indexes*::stat_index_size + dict_table_t::indexes*::stat_n_leaf_pages + (*) those are not always protected for + performance reasons */ unsigned stat_initialized:1; /*!< TRUE if statistics have been calculated the first time after database startup or table creation */ +#define DICT_TABLE_IN_USED -1 + lint memcached_sync_count; + /*!< count of how many handles are opened + to this table from memcached; DDL on the + table is NOT allowed until this count + goes to zero. If it's -1, means there's DDL + on the table, DML from memcached will be + blocked. */ ib_time_t stats_last_recalc; /*!< Timestamp of last recalc of the stats */ ib_uint32_t stat_persistent; diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index daeca1d8e44..6e906fa05b0 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -127,6 +127,8 @@ extern fil_addr_t fil_addr_null; at least up to this lsn */ #define FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID 34 /*!< starting from 4.1.x this contains the space id of the page */ +#define FIL_PAGE_SPACE_ID FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID + #define FIL_PAGE_DATA 38 /*!< start of the data on the page */ /* @} */ /** File page trailer @{ */ diff --git a/storage/innobase/include/fts0priv.h b/storage/innobase/include/fts0priv.h index c6aca27f6ec..b4d9e1d41ec 100644 --- a/storage/innobase/include/fts0priv.h +++ b/storage/innobase/include/fts0priv.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2013, 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 @@ -569,7 +569,10 @@ int fts_write_object_id( /*================*/ ib_id_t id, /*!< in: a table/index id */ - char* str) /*!< in: buffer to write the id to */ + char* str, /*!< in: buffer to write the id to */ + bool hex_format __attribute__((unused))) + /*!< in: true for fixed hex format, + false for old ambiguous format */ __attribute__((nonnull)); /******************************************************************//** Read the table id from the string generated by fts_write_object_id(). diff --git a/storage/innobase/include/fts0priv.ic b/storage/innobase/include/fts0priv.ic index 268bb7e2227..8ef877f267e 100644 --- a/storage/innobase/include/fts0priv.ic +++ b/storage/innobase/include/fts0priv.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2013, 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 @@ -32,9 +32,24 @@ int fts_write_object_id( /*================*/ ib_id_t id, /* in: a table/index id */ - char* str) /* in: buffer to write the id to */ + char* str, /* in: buffer to write the id to */ + bool hex_format __attribute__((unused))) + /* in: true for fixed hex format, + false for old ambiguous format */ { - // FIXME: Use ut_snprintf() +#ifdef _WIN32 + /* Use this to construct old(5.6.14 and 5.7.3) ambiguous + aux table names */ + DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name", + return(sprintf(str, "%016llu", id));); + + /* As above, but this is only for those tables failing to rename. */ + if (!hex_format) { + // FIXME: Use ut_snprintf(), so does following one. + return(sprintf(str, "%016llu", id)); + } +#endif /* _WIN32 */ + return(sprintf(str, UINT64PFx, id)); } @@ -48,6 +63,9 @@ fts_read_object_id( ib_id_t* id, /* out: an id */ const char* str) /* in: buffer to read from */ { + /* NOTE: this func doesn't care about whether current table + is set with HEX_NAME, the user of the id read here will check + if the id is HEX or DEC and do the right thing with it. */ return(sscanf(str, UINT64PFx, id) == 1); } diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 6fdad6a0b89..a02b8f1893a 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -414,16 +414,6 @@ innobase_fts_text_case_cmp( const void* p1, /*!< in: key */ const void* p2); /*!< in: node */ -/******************************************************************//** -compare two character string according to their charset. */ -UNIV_INTERN -int -innobase_fts_string_cmp( -/*====================*/ - const void* cs, /*!< in: Character set */ - const void* p1, /*!< in: key */ - const void* p2); /*!< in: node */ - /****************************************************************//** Get FTS field charset info from the field's prtype @return charset info */ diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h index dcdd4bdd8aa..b94f5a6fcec 100644 --- a/storage/innobase/include/log0recv.h +++ b/storage/innobase/include/log0recv.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1997, 2013, 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 @@ -31,6 +31,7 @@ Created 9/20/1997 Heikki Tuuri #include "buf0types.h" #include "hash0hash.h" #include "log0log.h" +#include #ifdef UNIV_HOTBACKUP extern ibool recv_replay_file_ops; @@ -367,6 +368,14 @@ struct recv_addr_t{ hash_node_t addr_hash;/*!< hash node in the hash bucket chain */ }; +struct recv_dblwr_t { + void add(byte* page); + + byte* find_first_page(ulint space_id); + + std::list pages; /* Pages from double write buffer */ +}; + /** Recovery system data structure */ struct recv_sys_t{ #ifndef UNIV_HOTBACKUP @@ -431,6 +440,8 @@ struct recv_sys_t{ hash_table_t* addr_hash;/*!< hash table of file addresses of pages */ ulint n_addrs;/*!< number of not processed hashed file addresses in the hash table */ + + recv_dblwr_t dblwr; }; /** The recovery system */ diff --git a/storage/innobase/include/mem0mem.h b/storage/innobase/include/mem0mem.h index c36ef06b554..f30034f3074 100644 --- a/storage/innobase/include/mem0mem.h +++ b/storage/innobase/include/mem0mem.h @@ -92,18 +92,35 @@ void mem_close(void); /*===========*/ +#ifdef UNIV_DEBUG /**************************************************************//** Use this macro instead of the corresponding function! Macro for memory heap creation. */ -#define mem_heap_create(N) mem_heap_create_func(\ - (N), MEM_HEAP_DYNAMIC, __FILE__, __LINE__) +# define mem_heap_create(N) mem_heap_create_func( \ + (N), __FILE__, __LINE__, MEM_HEAP_DYNAMIC) /**************************************************************//** Use this macro instead of the corresponding function! Macro for memory heap creation. */ -#define mem_heap_create_typed(N, T) mem_heap_create_func(\ - (N), (T), __FILE__, __LINE__) +# define mem_heap_create_typed(N, T) mem_heap_create_func( \ + (N), __FILE__, __LINE__, (T)) + +#else /* UNIV_DEBUG */ +/**************************************************************//** +Use this macro instead of the corresponding function! Macro for memory +heap creation. */ + +# define mem_heap_create(N) mem_heap_create_func( \ + (N), MEM_HEAP_DYNAMIC) +/**************************************************************//** +Use this macro instead of the corresponding function! Macro for memory +heap creation. */ + +# define mem_heap_create_typed(N, T) mem_heap_create_func( \ + (N), (T)) + +#endif /* UNIV_DEBUG */ /**************************************************************//** Use this macro instead of the corresponding function! Macro for memory heap freeing. */ @@ -124,9 +141,11 @@ mem_heap_create_func( this means that a single user buffer of size n will fit in the block, 0 creates a default size block */ - ulint type, /*!< in: heap type */ +#ifdef UNIV_DEBUG const char* file_name, /*!< in: file name where created */ - ulint line); /*!< in: line where created */ + ulint line, /*!< in: line where created */ +#endif /* UNIV_DEBUG */ + ulint type); /*!< in: heap type */ /*****************************************************************//** NOTE: Use the corresponding macro instead of this function. Frees the space occupied by a memory heap. In the debug version erases the heap memory @@ -218,8 +237,14 @@ Macro for memory buffer allocation */ #define mem_zalloc(N) memset(mem_alloc(N), 0, (N)) -#define mem_alloc(N) mem_alloc_func((N), NULL, __FILE__, __LINE__) -#define mem_alloc2(N,S) mem_alloc_func((N), (S), __FILE__, __LINE__) +#ifdef UNIV_DEBUG +#define mem_alloc(N) mem_alloc_func((N), __FILE__, __LINE__, NULL) +#define mem_alloc2(N,S) mem_alloc_func((N), __FILE__, __LINE__, (S)) +#else /* UNIV_DEBUG */ +#define mem_alloc(N) mem_alloc_func((N), NULL) +#define mem_alloc2(N,S) mem_alloc_func((N), (S)) +#endif /* UNIV_DEBUG */ + /***************************************************************//** NOTE: Use the corresponding macro instead of this function. Allocates a single buffer of memory from the dynamic memory of @@ -231,10 +256,12 @@ void* mem_alloc_func( /*===========*/ ulint n, /*!< in: requested size in bytes */ - ulint* size, /*!< out: allocated size in bytes, - or NULL */ +#ifdef UNIV_DEBUG const char* file_name, /*!< in: file name where created */ - ulint line); /*!< in: line where created */ + ulint line, /*!< in: line where created */ +#endif /* UNIV_DEBUG */ + ulint* size); /*!< out: allocated size in bytes, + or NULL */ /**************************************************************//** Use this macro instead of the corresponding function! @@ -343,8 +370,10 @@ mem_validate_all_blocks(void); /** The info structure stored at the beginning of a heap block */ struct mem_block_info_t { ulint magic_n;/* magic number for debugging */ +#ifdef UNIV_DEBUG char file_name[8];/* file name where the mem heap was created */ ulint line; /*!< line number where the mem heap was created */ +#endif /* UNIV_DEBUG */ UT_LIST_BASE_NODE_T(mem_block_t) base; /* In the first block in the the list this is the base node of the list of blocks; in subsequent blocks this is undefined */ diff --git a/storage/innobase/include/mem0mem.ic b/storage/innobase/include/mem0mem.ic index 7f0e128cc40..0d983d69e1a 100644 --- a/storage/innobase/include/mem0mem.ic +++ b/storage/innobase/include/mem0mem.ic @@ -28,21 +28,34 @@ Created 6/8/1994 Heikki Tuuri # include "mem0pool.h" #endif /* !UNIV_HOTBACKUP */ +#ifdef UNIV_DEBUG +# define mem_heap_create_block(heap, n, type, file_name, line) \ + mem_heap_create_block_func(heap, n, file_name, line, type) +# define mem_heap_create_at(N, file_name, line) \ + mem_heap_create_func(N, file_name, line, MEM_HEAP_DYNAMIC) +#else /* UNIV_DEBUG */ +# define mem_heap_create_block(heap, n, type, file_name, line) \ + mem_heap_create_block_func(heap, n, type) +# define mem_heap_create_at(N, file_name, line) \ + mem_heap_create_func(N, MEM_HEAP_DYNAMIC) +#endif /* UNIV_DEBUG */ /***************************************************************//** Creates a memory heap block where data can be allocated. @return own: memory heap block, NULL if did not succeed (only possible for MEM_HEAP_BTR_SEARCH type heaps) */ UNIV_INTERN mem_block_t* -mem_heap_create_block( -/*==================*/ +mem_heap_create_block_func( +/*=======================*/ mem_heap_t* heap, /*!< in: memory heap or NULL if first block should be created */ ulint n, /*!< in: number of bytes needed for user data */ - ulint type, /*!< in: type of heap: MEM_HEAP_DYNAMIC or - MEM_HEAP_BUFFER */ +#ifdef UNIV_DEBUG const char* file_name,/*!< in: file name where created */ - ulint line); /*!< in: line where created */ + ulint line, /*!< in: line where created */ +#endif /* UNIV_DEBUG */ + ulint type); /*!< in: type of heap: MEM_HEAP_DYNAMIC or + MEM_HEAP_BUFFER */ /******************************************************************//** Frees a block from a memory heap. */ UNIV_INTERN @@ -421,9 +434,11 @@ mem_heap_create_func( this means that a single user buffer of size n will fit in the block, 0 creates a default size block */ - ulint type, /*!< in: heap type */ +#ifdef UNIV_DEBUG const char* file_name, /*!< in: file name where created */ - ulint line) /*!< in: line where created */ + ulint line, /*!< in: line where created */ +#endif /* UNIV_DEBUG */ + ulint type) /*!< in: heap type */ { mem_block_t* block; @@ -509,15 +524,17 @@ void* mem_alloc_func( /*===========*/ ulint n, /*!< in: desired number of bytes */ - ulint* size, /*!< out: allocated size in bytes, - or NULL */ +#ifdef UNIV_DEBUG const char* file_name, /*!< in: file name where created */ - ulint line) /*!< in: line where created */ + ulint line, /*!< in: line where created */ +#endif /* UNIV_DEBUG */ + ulint* size) /*!< out: allocated size in bytes, + or NULL */ { mem_heap_t* heap; void* buf; - heap = mem_heap_create_func(n, MEM_HEAP_DYNAMIC, file_name, line); + heap = mem_heap_create_at(n, file_name, line); /* Note that as we created the first block in the heap big enough for the buffer requested by the caller, the buffer will be in the diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index f19d61e0137..8e2948e2d68 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -1,6 +1,6 @@ /*********************************************************************** -Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, Percona Inc. Portions of this file contain modifications contributed and copyrighted @@ -150,6 +150,10 @@ enum os_file_create_t { #define OS_FILE_INSUFFICIENT_RESOURCE 78 #define OS_FILE_AIO_INTERRUPTED 79 #define OS_FILE_OPERATION_ABORTED 80 + +#define OS_FILE_ACCESS_VIOLATION 81 + +#define OS_FILE_ERROR_MAX 100 /* @} */ /** Types for aio operations @{ */ @@ -381,7 +385,8 @@ enum os_file_type_t { OS_FILE_TYPE_UNKNOWN = 0, OS_FILE_TYPE_FILE, /* regular file */ OS_FILE_TYPE_DIR, /* directory */ - OS_FILE_TYPE_LINK /* symbolic link */ + OS_FILE_TYPE_LINK, /* symbolic link */ + OS_FILE_TYPE_BLOCK /* block device */ }; /* Maximum path string length in bytes when referring to tables with in the diff --git a/storage/innobase/include/os0sync.h b/storage/innobase/include/os0sync.h index d3ce68253ec..ea3f2a06db5 100644 --- a/storage/innobase/include/os0sync.h +++ b/storage/innobase/include/os0sync.h @@ -374,6 +374,9 @@ compare to, new_val is the value to swap in. */ # define os_compare_and_swap_lint(ptr, old_val, new_val) \ os_compare_and_swap(ptr, old_val, new_val) +# define os_compare_and_swap_uint32(ptr, old_val, new_val) \ + os_compare_and_swap(ptr, old_val, new_val) + # ifdef HAVE_IB_ATOMIC_PTHREAD_T_GCC # define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ os_compare_and_swap(ptr, old_val, new_val) @@ -395,6 +398,9 @@ amount of increment. */ # define os_atomic_increment_lint(ptr, amount) \ os_atomic_increment(ptr, amount) +# define os_atomic_increment_uint32(ptr, amount ) \ + os_atomic_increment(ptr, amount) + # define os_atomic_increment_ulint(ptr, amount) \ os_atomic_increment(ptr, amount) @@ -407,6 +413,9 @@ amount to decrement. */ # define os_atomic_decrement(ptr, amount) \ __sync_sub_and_fetch(ptr, amount) +# define os_atomic_decrement_uint32(ptr, amount) \ + os_atomic_decrement(ptr, amount) + # define os_atomic_decrement_lint(ptr, amount) \ os_atomic_decrement(ptr, amount) @@ -439,6 +448,9 @@ intrinsics and running on Solaris >= 10 use Solaris atomics */ Returns true if swapped, ptr is pointer to target, old_val is value to compare to, new_val is the value to swap in. */ +# define os_compare_and_swap_uint32(ptr, old_val, new_val) \ + (atomic_cas_32(ptr, old_val, new_val) == old_val) + # define os_compare_and_swap_ulint(ptr, old_val, new_val) \ (atomic_cas_ulong(ptr, old_val, new_val) == old_val) @@ -467,6 +479,9 @@ compare to, new_val is the value to swap in. */ Returns the resulting value, ptr is pointer to target, amount is the amount of increment. */ +# define os_atomic_increment_uint32(ptr, amount) \ + atomic_add_32_nv(ptr, amount) + # define os_atomic_increment_ulint(ptr, amount) \ atomic_add_long_nv(ptr, amount) @@ -479,6 +494,9 @@ amount of increment. */ /* Returns the resulting value, ptr is pointer to target, amount is the amount to decrement. */ +# define os_atomic_decrement_uint32(ptr, amount) \ + os_atomic_increment_uint32(ptr, -(amount)) + # define os_atomic_decrement_lint(ptr, amount) \ os_atomic_increment_ulint((ulong_t*) ptr, -(amount)) @@ -555,6 +573,9 @@ win_cmp_and_xchg_dword( Returns true if swapped, ptr is pointer to target, old_val is value to compare to, new_val is the value to swap in. */ +# define os_compare_and_swap_uint32(ptr, old_val, new_val) \ + (win_cmp_and_xchg_dword(ptr, new_val, old_val) == old_val) + # define os_compare_and_swap_ulint(ptr, old_val, new_val) \ (win_cmp_and_xchg_ulint(ptr, new_val, old_val) == old_val) @@ -576,6 +597,9 @@ amount of increment. */ # define os_atomic_increment_lint(ptr, amount) \ (win_xchg_and_add(ptr, amount) + amount) +# define os_atomic_increment_uint32(ptr, amount) \ + ((ulint) _InterlockedExchangeAdd((long*) ptr, amount)) + # define os_atomic_increment_ulint(ptr, amount) \ ((ulint) (win_xchg_and_add((lint*) ptr, (lint) amount) + amount)) @@ -588,6 +612,9 @@ amount of increment. */ Returns the resulting value, ptr is pointer to target, amount is the amount to decrement. There is no atomic substract function on Windows */ +# define os_atomic_decrement_uint32(ptr, amount) \ + ((ulint) _InterlockedExchangeAdd((long*) ptr, (-amount))) + # define os_atomic_decrement_lint(ptr, amount) \ (win_xchg_and_add(ptr, -(lint) amount) - amount) diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index fb21aaec778..b572f7abb49 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -1102,6 +1102,14 @@ page_find_rec_with_heap_no( /*=======================*/ const page_t* page, /*!< in: index page */ ulint heap_no);/*!< in: heap number */ +/** Get the last non-delete-marked record on a page. +@param[in] page index tree leaf page +@return the last record, not delete-marked +@retval infimum record if all records are delete-marked */ + +const rec_t* +page_find_rec_max_not_deleted( + const page_t* page); #ifdef UNIV_MATERIALIZE #undef UNIV_INLINE #define UNIV_INLINE UNIV_INLINE_ORIGINAL diff --git a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic index 1410f21b670..9b81156708f 100644 --- a/storage/innobase/include/page0page.ic +++ b/storage/innobase/include/page0page.ic @@ -414,6 +414,8 @@ page_rec_is_user_rec( /*=================*/ const rec_t* rec) /*!< in: record */ { + ut_ad(page_rec_check(rec)); + return(page_rec_is_user_rec_low(page_offset(rec))); } @@ -426,6 +428,8 @@ page_rec_is_supremum( /*=================*/ const rec_t* rec) /*!< in: record */ { + ut_ad(page_rec_check(rec)); + return(page_rec_is_supremum_low(page_offset(rec))); } @@ -438,6 +442,8 @@ page_rec_is_infimum( /*================*/ const rec_t* rec) /*!< in: record */ { + ut_ad(page_rec_check(rec)); + return(page_rec_is_infimum_low(page_offset(rec))); } diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h index 2a84aee7a6f..8e7d5ff2d48 100644 --- a/storage/innobase/include/rem0rec.h +++ b/storage/innobase/include/rem0rec.h @@ -440,13 +440,24 @@ rec_get_offsets_func( ulint n_fields,/*!< in: maximum number of initialized fields (ULINT_UNDEFINED if all fields) */ - mem_heap_t** heap, /*!< in/out: memory heap */ +#ifdef UNIV_DEBUG const char* file, /*!< in: file name where called */ - ulint line) /*!< in: line number where called */ - __attribute__((nonnull(1,2,5,6),warn_unused_result)); + ulint line, /*!< in: line number where called */ +#endif /* UNIV_DEBUG */ + mem_heap_t** heap) /*!< in/out: memory heap */ +#ifdef UNIV_DEBUG + __attribute__((nonnull(1,2,5,7),warn_unused_result)); +#else /* UNIV_DEBUG */ + __attribute__((nonnull(1,2,5),warn_unused_result)); +#endif /* UNIV_DEBUG */ -#define rec_get_offsets(rec,index,offsets,n,heap) \ - rec_get_offsets_func(rec,index,offsets,n,heap,__FILE__,__LINE__) +#ifdef UNIV_DEBUG +# define rec_get_offsets(rec,index,offsets,n,heap) \ + rec_get_offsets_func(rec,index,offsets,n,__FILE__,__LINE__,heap) +#else /* UNIV_DEBUG */ +# define rec_get_offsets(rec, index, offsets, n, heap) \ + rec_get_offsets_func(rec, index, offsets, n, heap) +#endif /* UNIV_DEBUG */ /******************************************************//** The following function determines the offsets to each field diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 8cbf52e8629..3bb38d62ecf 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2008, 2009, Google Inc. Copyright (c) 2009, Percona Inc. @@ -362,8 +362,8 @@ extern ulong srv_max_purge_lag_delay; extern ulong srv_replication_delay; /*-------------------------------------------*/ -extern ibool srv_print_innodb_monitor; -extern ibool srv_print_innodb_lock_monitor; +extern my_bool srv_print_innodb_monitor; +extern my_bool srv_print_innodb_lock_monitor; extern ibool srv_print_innodb_tablespace_monitor; extern ibool srv_print_verbose_log; #define DEPRECATED_MSG_INNODB_TABLE_MONITOR \ diff --git a/storage/innobase/include/sync0rw.h b/storage/innobase/include/sync0rw.h index c268098d1ea..34cd8ef4bd6 100644 --- a/storage/innobase/include/sync0rw.h +++ b/storage/innobase/include/sync0rw.h @@ -181,6 +181,9 @@ unlocking, not the corresponding function. */ # define rw_lock_s_lock_gen(M, P) \ rw_lock_s_lock_func((M), (P), __FILE__, __LINE__) +# define rw_lock_s_lock_gen_nowait(M, P) \ + rw_lock_s_lock_low((M), (P), __FILE__, __LINE__) + # define rw_lock_s_lock_nowait(M, F, L) \ rw_lock_s_lock_low((M), 0, (F), (L)) @@ -243,6 +246,9 @@ unlocking, not the corresponding function. */ # define rw_lock_s_lock_gen(M, P) \ pfs_rw_lock_s_lock_func((M), (P), __FILE__, __LINE__) +# define rw_lock_s_lock_gen_nowait(M, P) \ + pfs_rw_lock_s_lock_low((M), (P), __FILE__, __LINE__) + # define rw_lock_s_lock_nowait(M, F, L) \ pfs_rw_lock_s_lock_low((M), 0, (F), (L)) diff --git a/storage/innobase/include/sync0rw.ic b/storage/innobase/include/sync0rw.ic index 8786ad84643..1ddae5e6c58 100644 --- a/storage/innobase/include/sync0rw.ic +++ b/storage/innobase/include/sync0rw.ic @@ -380,8 +380,6 @@ rw_lock_x_lock_func_nowait( const char* file_name,/*!< in: file name where lock requested */ ulint line) /*!< in: line where requested */ { - os_thread_id_t curr_thread = os_thread_get_curr_id(); - ibool success; #ifdef INNODB_RW_LOCKS_USE_ATOMICS @@ -401,7 +399,8 @@ rw_lock_x_lock_func_nowait( rw_lock_set_writer_id_and_recursion_flag(lock, TRUE); } else if (lock->recursive - && os_thread_eq(lock->writer_thread, curr_thread)) { + && os_thread_eq(lock->writer_thread, + os_thread_get_curr_id())) { /* Relock: this lock_word modification is safe since no other threads can modify (lock, unlock, or reserve) lock_word while there is an exclusive writer and this is the writer thread. */ diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index f580901237f..34e4c0067e2 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -836,8 +836,7 @@ struct trx_t{ when trx->in_rw_trx_list. Initially set to TRX_ID_MAX. */ - time_t start_time; /*!< time the trx object was created - or the state last time became + time_t start_time; /*!< time the trx state last time became TRX_STATE_ACTIVE */ trx_id_t id; /*!< transaction id */ XID xid; /*!< X/Open XA transaction diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index 9b5fffe81e8..9ab123aa4f2 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -44,7 +44,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 5 #define INNODB_VERSION_MINOR 6 -#define INNODB_VERSION_BUGFIX 15 +#define INNODB_VERSION_BUGFIX 16 /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; @@ -171,7 +171,6 @@ command. Not tested on Windows. */ #define UNIV_COMPILE_TEST_FUNCS */ -#undef UNIV_SYNC_DEBUG #if defined(HAVE_valgrind)&& defined(HAVE_VALGRIND_MEMCHECK_H) # define UNIV_DEBUG_VALGRIND #endif /* HAVE_VALGRIND */ @@ -433,7 +432,7 @@ macro ULINTPF. */ # define UINT32PF "%I32u" # define INT64PF "%I64d" # define UINT64PF "%I64u" -# define UINT64PFx "%016I64u" +# define UINT64PFx "%016I64x" # define DBUG_LSN_PF "%llu" typedef __int64 ib_int64_t; typedef unsigned __int64 ib_uint64_t; diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index e7a643b516a..08f50f70fd4 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1997, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. This program is free software; you can redistribute it and/or modify it under @@ -24,6 +24,11 @@ Recovery Created 9/20/1997 Heikki Tuuri *******************************************************/ +// First include (the generated) my_config.h, to get correct platform defines. +#include "my_config.h" +#include // Solaris/x86 header file bug + +#include #include "log0recv.h" #ifdef UNIV_NONINL @@ -52,6 +57,7 @@ Created 9/20/1997 Heikki Tuuri # include "sync0sync.h" #else /* !UNIV_HOTBACKUP */ + /** This is set to FALSE if the backup was originally taken with the ibbackup --include regexp option: then we do not want to create tables in directories which were not included */ @@ -422,6 +428,9 @@ recv_sys_init( recv_max_page_lsn = 0; + /* Call the constructor for recv_sys_t::dblwr member */ + new (&recv_sys->dblwr) recv_dblwr_t(); + mutex_exit(&(recv_sys->mutex)); } @@ -1311,13 +1320,22 @@ recv_parse_or_apply_log_rec_body( ptr = mlog_parse_string(ptr, end_ptr, page, page_zip); break; case MLOG_FILE_RENAME: - ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type, - space_id, 0); + /* Do not rerun file-based log entries if this is + IO completion from a page read. */ + if (page == NULL) { + ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type, + space_id, 0); + } break; case MLOG_FILE_CREATE: case MLOG_FILE_DELETE: case MLOG_FILE_CREATE2: - ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type, 0, 0); + /* Do not rerun file-based log entries if this is + IO completion from a page read. */ + if (page == NULL) { + ptr = fil_op_log_parse_or_replay(ptr, end_ptr, + type, 0, 0); + } break; case MLOG_ZIP_WRITE_NODE_PTR: ut_ad(!page || page_type == FIL_PAGE_INDEX); @@ -2953,6 +2971,8 @@ recv_init_crash_recovery(void) ib_logf(IB_LOG_LEVEL_INFO, "Reading tablespace information from the .ibd files..."); + buf_dblwr_init_or_load_pages(true); + fil_load_single_table_tablespaces(); /* If we are using the doublewrite method, we will @@ -2968,7 +2988,7 @@ recv_init_crash_recovery(void) ib_logf(IB_LOG_LEVEL_INFO, "from the doublewrite buffer..."); - buf_dblwr_init_or_restore_pages(TRUE); + buf_dblwr_process(); /* Spawn the background thread to flush dirty pages from the buffer pools. */ @@ -3262,7 +3282,7 @@ recv_recovery_from_checkpoint_start_func( if (!recv_needed_recovery && !srv_read_only_mode) { /* Init the doublewrite buffer memory structure */ - buf_dblwr_init_or_restore_pages(FALSE); + buf_dblwr_init_or_load_pages(false); } } @@ -3964,3 +3984,46 @@ recv_recovery_from_archive_finish(void) recv_recovery_from_backup_on = FALSE; } #endif /* UNIV_LOG_ARCHIVE */ + + +void recv_dblwr_t::add(byte* page) +{ + pages.push_back(page); +} + +byte* recv_dblwr_t::find_first_page(ulint space_id) +{ + std::vector matches; + byte* result = 0; + + for (std::list::iterator i = pages.begin(); + i != pages.end(); ++i) { + + if ((page_get_space_id(*i) == space_id) + && (page_get_page_no(*i) == 0)) { + matches.push_back(*i); + } + } + + if (matches.size() == 1) { + result = matches[0]; + } else if (matches.size() > 1) { + + lsn_t max_lsn = 0; + lsn_t page_lsn = 0; + + for (std::vector::iterator i = matches.begin(); + i != matches.end(); ++i) { + + page_lsn = mach_read_from_8(*i + FIL_PAGE_LSN); + + if (page_lsn > max_lsn) { + max_lsn = page_lsn; + result = *i; + } + } + } + + return(result); +} + diff --git a/storage/innobase/mem/mem0mem.cc b/storage/innobase/mem/mem0mem.cc index e0e6220f4d8..e066aff5b30 100644 --- a/storage/innobase/mem/mem0mem.cc +++ b/storage/innobase/mem/mem0mem.cc @@ -299,15 +299,17 @@ Creates a memory heap block where data can be allocated. for MEM_HEAP_BTR_SEARCH type heaps) */ UNIV_INTERN mem_block_t* -mem_heap_create_block( -/*==================*/ +mem_heap_create_block_func( +/*=======================*/ mem_heap_t* heap, /*!< in: memory heap or NULL if first block should be created */ ulint n, /*!< in: number of bytes needed for user data */ - ulint type, /*!< in: type of heap: MEM_HEAP_DYNAMIC or - MEM_HEAP_BUFFER */ +#ifdef UNIV_DEBUG const char* file_name,/*!< in: file name where created */ - ulint line) /*!< in: line where created */ + ulint line, /*!< in: line where created */ +#endif /* UNIV_DEBUG */ + ulint type) /*!< in: type of heap: MEM_HEAP_DYNAMIC or + MEM_HEAP_BUFFER */ { #ifndef UNIV_HOTBACKUP buf_block_t* buf_block = NULL; @@ -368,8 +370,9 @@ mem_heap_create_block( #endif /* !UNIV_HOTBACKUP */ block->magic_n = MEM_BLOCK_MAGIC_N; - ut_strlcpy_rev(block->file_name, file_name, sizeof(block->file_name)); - block->line = line; + ut_d(ut_strlcpy_rev(block->file_name, file_name, + sizeof(block->file_name))); + ut_d(block->line = line); #ifdef MEM_PERIODIC_CHECK mutex_enter(&(mem_comm_pool->mutex)); diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index d07d381fb8f..d3f1980aeed 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -465,8 +465,10 @@ os_file_get_last_error_low( return(OS_FILE_INSUFFICIENT_RESOURCE); } else if (err == ERROR_OPERATION_ABORTED) { return(OS_FILE_OPERATION_ABORTED); + } else if (err == ERROR_ACCESS_DENIED) { + return(OS_FILE_ACCESS_VIOLATION); } else { - return(100 + err); + return(OS_FILE_ERROR_MAX + err); } #else int err = errno; @@ -540,8 +542,10 @@ os_file_get_last_error_low( return(OS_FILE_AIO_INTERRUPTED); } break; + case EACCES: + return(OS_FILE_ACCESS_VIOLATION); } - return(100 + err); + return(OS_FILE_ERROR_MAX + err); #endif } @@ -619,6 +623,7 @@ os_file_handle_error_cond_exit( case OS_FILE_PATH_ERROR: case OS_FILE_ALREADY_EXISTS: + case OS_FILE_ACCESS_VIOLATION: return(FALSE); @@ -3166,32 +3171,43 @@ os_file_get_status( return(DB_FAIL); - } else if (S_ISDIR(statinfo.st_mode)) { + } + + switch (statinfo.st_mode & S_IFMT) { + case S_IFDIR: stat_info->type = OS_FILE_TYPE_DIR; - } else if (S_ISLNK(statinfo.st_mode)) { + break; + case S_IFLNK: stat_info->type = OS_FILE_TYPE_LINK; - } else if (S_ISREG(statinfo.st_mode)) { + break; + case S_IFBLK: + stat_info->type = OS_FILE_TYPE_BLOCK; + break; + case S_IFREG: stat_info->type = OS_FILE_TYPE_FILE; - - if (check_rw_perm) { - int fh; - int access; - - access = !srv_read_only_mode ? O_RDWR : O_RDONLY; - - fh = ::open(path, access, os_innodb_umask); - - if (fh == -1) { - stat_info->rw_perm = false; - } else { - stat_info->rw_perm = true; - close(fh); - } - } - } else { + break; + default: stat_info->type = OS_FILE_TYPE_UNKNOWN; } + + if (check_rw_perm && (stat_info->type == OS_FILE_TYPE_FILE + || stat_info->type == OS_FILE_TYPE_BLOCK)) { + int fh; + int access; + + access = !srv_read_only_mode ? O_RDWR : O_RDONLY; + + fh = ::open(path, access, os_innodb_umask); + + if (fh == -1) { + stat_info->rw_perm = false; + } else { + stat_info->rw_perm = true; + close(fh); + } + } + #endif /* _WIN_ */ stat_info->ctime = statinfo.st_ctime; diff --git a/storage/innobase/page/page0cur.cc b/storage/innobase/page/page0cur.cc index efce1f10cae..f5f7e1299ce 100644 --- a/storage/innobase/page/page0cur.cc +++ b/storage/innobase/page/page0cur.cc @@ -977,7 +977,8 @@ page_cur_insert_rec_low( == (ibool) !!page_is_comp(page)); ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX); ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) - == index->id || recv_recovery_is_on() || mtr->inside_ibuf); + == index->id || recv_recovery_is_on() + || (mtr ? mtr->inside_ibuf : dict_index_is_ibuf(index))); ut_ad(!page_rec_is_supremum(current_rec)); @@ -1204,7 +1205,8 @@ page_cur_insert_rec_zip( ut_ad(page_is_comp(page)); ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX); ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) - == index->id || mtr->inside_ibuf || recv_recovery_is_on()); + == index->id || recv_recovery_is_on() + || (mtr ? mtr->inside_ibuf : dict_index_is_ibuf(index))); ut_ad(!page_cur_is_after_last(cursor)); #ifdef UNIV_ZIP_DEBUG @@ -1977,7 +1979,8 @@ page_cur_delete_rec( const dict_index_t* index, /*!< in: record descriptor */ const ulint* offsets,/*!< in: rec_get_offsets( cursor->rec, index) */ - mtr_t* mtr) /*!< in: mini-transaction handle */ + mtr_t* mtr) /*!< in: mini-transaction handle + or NULL */ { page_dir_slot_t* cur_dir_slot; page_dir_slot_t* prev_slot; @@ -2006,7 +2009,8 @@ page_cur_delete_rec( ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table)); ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX); ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) - == index->id || mtr->inside_ibuf || recv_recovery_is_on()); + == index->id || recv_recovery_is_on() + || (mtr ? mtr->inside_ibuf : dict_index_is_ibuf(index))); /* The record must not be the supremum or infimum record. */ ut_ad(page_rec_is_user_rec(current_rec)); diff --git a/storage/innobase/page/page0page.cc b/storage/innobase/page/page0page.cc index 2faf804279c..bd5fb36af8f 100644 --- a/storage/innobase/page/page0page.cc +++ b/storage/innobase/page/page0page.cc @@ -2779,3 +2779,35 @@ page_delete_rec( return(no_compress_needed); } +/** Get the last non-delete-marked record on a page. +@param[in] page index tree leaf page +@return the last record, not delete-marked +@retval infimum record if all records are delete-marked */ + +const rec_t* +page_find_rec_max_not_deleted( + const page_t* page) +{ + const rec_t* rec = page_get_infimum_rec(page); + const rec_t* prev_rec = NULL; // remove warning + + /* Because the page infimum is never delete-marked, + prev_rec will always be assigned to it first. */ + ut_ad(!rec_get_deleted_flag(rec, page_rec_is_comp(rec))); + if (page_is_comp(page)) { + do { + if (!rec_get_deleted_flag(rec, true)) { + prev_rec = rec; + } + rec = page_rec_get_next_low(rec, true); + } while (rec != page + PAGE_NEW_SUPREMUM); + } else { + do { + if (!rec_get_deleted_flag(rec, false)) { + prev_rec = rec; + } + rec = page_rec_get_next_low(rec, false); + } while (rec != page + PAGE_OLD_SUPREMUM); + } + return(prev_rec); +} diff --git a/storage/innobase/page/page0zip.cc b/storage/innobase/page/page0zip.cc index 52dcbf64183..cfe67e49b68 100644 --- a/storage/innobase/page/page0zip.cc +++ b/storage/innobase/page/page0zip.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2005, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2005, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. This program is free software; you can redistribute it and/or modify it under @@ -24,6 +24,9 @@ Compressed page interface Created June 2005 by Marko Makela *******************************************************/ +// First include (the generated) my_config.h, to get correct platform defines. +#include "my_config.h" + #include using namespace std; @@ -1567,9 +1570,8 @@ page_zip_fields_free( dict_table_t* table = index->table; os_fast_mutex_free(&index->zip_pad.mutex); mem_heap_free(index->heap); - mutex_free(&(table->autoinc_mutex)); - ut_free(table->name); - mem_heap_free(table->heap); + + dict_mem_table_free(table); } } @@ -4894,8 +4896,12 @@ page_zip_verify_checksum( /* declare empty pages non-corrupted */ if (stored == 0) { /* make sure that the page is really empty */ - ut_d(ulint i; for (i = 0; i < size; i++) { - ut_a(*((const char*) data + i) == 0); }); + ulint i; + for (i = 0; i < size; i++) { + if (*((const char*) data + i) != 0) { + return(FALSE); + } + } return(TRUE); } diff --git a/storage/innobase/pars/pars0pars.cc b/storage/innobase/pars/pars0pars.cc index e0bc00fad0d..509755c76fa 100644 --- a/storage/innobase/pars/pars0pars.cc +++ b/storage/innobase/pars/pars0pars.cc @@ -1988,6 +1988,12 @@ pars_create_table( } } + /* Set the flags2 when create table or alter tables */ + flags2 |= DICT_TF2_FTS_AUX_HEX_NAME; + DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name", + flags2 &= ~DICT_TF2_FTS_AUX_HEX_NAME;); + + n_cols = que_node_list_get_len(column_defs); table = dict_mem_table_create( diff --git a/storage/xtradb/plugin_exports b/storage/innobase/plugin_exports similarity index 100% rename from storage/xtradb/plugin_exports rename to storage/innobase/plugin_exports diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc index 43072159b9e..0d7b7c16785 100644 --- a/storage/innobase/rem/rem0rec.cc +++ b/storage/innobase/rem/rem0rec.cc @@ -543,9 +543,11 @@ rec_get_offsets_func( ulint n_fields,/*!< in: maximum number of initialized fields (ULINT_UNDEFINED if all fields) */ - mem_heap_t** heap, /*!< in/out: memory heap */ +#ifdef UNIV_DEBUG const char* file, /*!< in: file name where called */ - ulint line) /*!< in: line number where called */ + ulint line, /*!< in: line number where called */ +#endif /* UNIV_DEBUG */ + mem_heap_t** heap) /*!< in/out: memory heap */ { ulint n; ulint size; @@ -590,9 +592,8 @@ rec_get_offsets_func( if (UNIV_UNLIKELY(!offsets) || UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) { if (UNIV_UNLIKELY(!*heap)) { - *heap = mem_heap_create_func(size * sizeof(ulint), - MEM_HEAP_DYNAMIC, - file, line); + *heap = mem_heap_create_at(size * sizeof(ulint), + file, line); } offsets = static_cast( mem_heap_alloc(*heap, size * sizeof(ulint))); diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index 087d2152826..d88fa93aaf9 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2010, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2010, 2013, 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 @@ -1431,11 +1431,17 @@ row_fts_merge_insert( ins_ctx.ins_graph = static_cast(mem_heap_alloc(heap, n_bytes)); memset(ins_ctx.ins_graph, 0x0, n_bytes); + /* We should set the flags2 with aux_table_name here, + in order to get the correct aux table names. */ + index->table->flags2 |= DICT_TF2_FTS_AUX_HEX_NAME; + DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name", + index->table->flags2 &= ~DICT_TF2_FTS_AUX_HEX_NAME;); + ins_ctx.fts_table.type = FTS_INDEX_TABLE; ins_ctx.fts_table.index_id = index->id; ins_ctx.fts_table.table_id = table->id; ins_ctx.fts_table.parent = index->table->name; - ins_ctx.fts_table.table = NULL; + ins_ctx.fts_table.table = index->table; for (i = 0; i < fts_sort_pll_degree; i++) { if (psort_info[i].merge_file[id]->n_rec == 0) { diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index c18ef9ee250..e9bbeea240f 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -78,11 +78,12 @@ struct row_log_buf_t { mrec_buf_t buf; /*!< buffer for accessing a record that spans two blocks */ ulint blocks; /*!< current position in blocks */ - ulint bytes; /*!< current position within buf */ + ulint bytes; /*!< current position within block */ ulonglong total; /*!< logical position, in bytes from the start of the row_log_table log; 0 for row_log_online_op() and row_log_apply(). */ + ulint size; /*!< allocated size of block */ }; /** Tracks BLOB allocation during online ALTER TABLE */ @@ -193,9 +194,47 @@ struct row_log_t { or by index->lock X-latch only */ row_log_buf_t head; /*!< reader context; protected by MDL only; modifiable by row_log_apply_ops() */ - ulint size; /*!< allocated size */ }; + +/** Allocate the memory for the log buffer. +@param[in,out] log_buf Buffer used for log operation +@return TRUE if success, false if not */ +static __attribute__((warn_unused_result)) +bool +row_log_block_allocate( + row_log_buf_t& log_buf) +{ + DBUG_ENTER("row_log_block_allocate"); + if (log_buf.block == NULL) { + log_buf.size = srv_sort_buf_size; + log_buf.block = (byte*) os_mem_alloc_large(&log_buf.size); + DBUG_EXECUTE_IF("simulate_row_log_allocation_failure", + if (log_buf.block) + os_mem_free_large(log_buf.block, log_buf.size); + log_buf.block = NULL;); + if (!log_buf.block) { + DBUG_RETURN(false); + } + } + DBUG_RETURN(true); +} + +/** Free the log buffer. +@param[in,out] log_buf Buffer used for log operation */ +static +void +row_log_block_free( + row_log_buf_t& log_buf) +{ + DBUG_ENTER("row_log_block_free"); + if (log_buf.block != NULL) { + os_mem_free_large(log_buf.block, log_buf.size); + log_buf.block = NULL; + } + DBUG_VOID_RETURN; +} + /******************************************************//** Logs an operation to a secondary index that is (or was) being created. */ UNIV_INTERN @@ -247,6 +286,11 @@ row_log_online_op( log->max_trx = trx_id; } + if (!row_log_block_allocate(log->tail)) { + log->error = DB_OUT_OF_MEMORY; + goto err_exit; + } + UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf); ut_ad(log->tail.bytes < srv_sort_buf_size); @@ -318,6 +362,7 @@ write_failed: } UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf); +err_exit: mutex_exit(&log->mutex); } @@ -352,10 +397,16 @@ row_log_table_open( UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf); if (log->error != DB_SUCCESS) { +err_exit: mutex_exit(&log->mutex); return(NULL); } + if (!row_log_block_allocate(log->tail)) { + log->error = DB_OUT_OF_MEMORY; + goto err_exit; + } + ut_ad(log->tail.bytes < srv_sort_buf_size); *avail = srv_sort_buf_size - log->tail.bytes; @@ -2306,6 +2357,11 @@ all_done: ut_ad(dict_index_is_online_ddl(index)); + if (!row_log_block_allocate(index->online_log->head)) { + error = DB_OUT_OF_MEMORY; + goto func_exit; + } + success = os_file_read_no_error_handling( OS_FILE_FROM_FD(index->online_log->fd), index->online_log->head.block, ofs, @@ -2509,6 +2565,7 @@ func_exit: mem_heap_free(offsets_heap); mem_heap_free(heap); + row_log_block_free(index->online_log->head); ut_free(offsets); return(error); } @@ -2582,9 +2639,7 @@ row_log_allocate( const ulint* col_map)/*!< in: mapping of old column numbers to new ones, or NULL if !table */ { - byte* buf; row_log_t* log; - ulint size; DBUG_ENTER("row_log_allocate"); ut_ad(!dict_index_is_online_ddl(index)); @@ -2596,17 +2651,14 @@ row_log_allocate( #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(dict_index_get_lock(index), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - size = 2 * srv_sort_buf_size + sizeof *log; - buf = (byte*) os_mem_alloc_large(&size); - if (!buf) { + log = (row_log_t*) ut_malloc(sizeof *log); + if (!log) { DBUG_RETURN(false); } - log = (row_log_t*) &buf[2 * srv_sort_buf_size]; - log->size = size; log->fd = row_merge_file_create_low(); if (log->fd < 0) { - os_mem_free_large(buf, size); + ut_free(log); DBUG_RETURN(false); } mutex_create(index_online_log_key, &log->mutex, @@ -2618,10 +2670,9 @@ row_log_allocate( log->col_map = col_map; log->error = DB_SUCCESS; log->max_trx = 0; - log->head.block = buf; - log->tail.block = buf + srv_sort_buf_size; log->tail.blocks = log->tail.bytes = 0; log->tail.total = 0; + log->tail.block = log->head.block = NULL; log->head.blocks = log->head.bytes = 0; log->head.total = 0; dict_index_set_online_status(index, ONLINE_INDEX_CREATION); @@ -2646,9 +2697,11 @@ row_log_free( MONITOR_ATOMIC_DEC(MONITOR_ONLINE_CREATE_INDEX); delete log->blobs; + row_log_block_free(log->tail); + row_log_block_free(log->head); row_merge_file_destroy_low(log->fd); mutex_free(&log->mutex); - os_mem_free_large(log->head.block, log->size); + ut_free(log); log = 0; } @@ -3074,6 +3127,11 @@ next_block: goto interrupted; } + error = index->online_log->error; + if (error != DB_SUCCESS) { + goto func_exit; + } + if (dict_index_is_corrupted(index)) { error = DB_INDEX_CORRUPT; goto func_exit; @@ -3130,6 +3188,11 @@ all_done: log_free_check(); + if (!row_log_block_allocate(index->online_log->head)) { + error = DB_OUT_OF_MEMORY; + goto func_exit; + } + success = os_file_read_no_error_handling( OS_FILE_FROM_FD(index->online_log->fd), index->online_log->head.block, ofs, @@ -3330,6 +3393,7 @@ func_exit: mem_heap_free(heap); mem_heap_free(offsets_heap); + row_log_block_free(index->online_log->head); ut_free(offsets); return(error); } diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 2a60790f29c..93d13ea49ee 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1277,7 +1277,9 @@ row_insert_for_mysql( " newraw is replaced\n" "InnoDB: with raw, and innodb_force_... is removed.\n", stderr); - + if(srv_force_recovery) { + return(DB_READ_ONLY); + } return(DB_ERROR); } @@ -1662,7 +1664,9 @@ row_update_for_mysql( " is replaced\n" "InnoDB: with raw, and innodb_force_... is removed.\n", stderr); - + if(srv_force_recovery) { + return(DB_READ_ONLY); + } return(DB_ERROR); } @@ -3240,7 +3244,6 @@ row_truncate_table_for_mysql( ut_a(trx->dict_operation_lock_mode == 0); /* Prevent foreign key checks etc. while we are truncating the table */ - row_mysql_lock_data_dictionary(trx); ut_ad(mutex_own(&(dict_sys->mutex))); @@ -3304,6 +3307,25 @@ row_truncate_table_for_mysql( goto funct_exit; } + /* Check if memcached plugin is running on this table. if is, we don't + allow truncate this table. */ + if (table->memcached_sync_count != 0) { + ut_print_timestamp(stderr); + fputs(" InnoDB: Cannot truncate table ", stderr); + ut_print_name(stderr, trx, TRUE, table->name); + fputs(" by DROP+CREATE\n" + "InnoDB: because there are memcached operations" + " running on it.\n", + stderr); + err = DB_ERROR; + + goto funct_exit; + } else { + /* We need to set this counter to -1 for blocking + memcached operations. */ + table->memcached_sync_count = DICT_TABLE_IN_DDL; + } + /* Remove all locks except the table-level X lock. */ lock_remove_all_on_table(table, FALSE); @@ -3487,6 +3509,7 @@ next_rec: fts_table.name = table->name; fts_table.id = new_id; + fts_table.flags2 = table->flags2; err = fts_create_common_tables( trx, &fts_table, table->name, TRUE); @@ -3631,6 +3654,12 @@ next_rec: funct_exit: + if (table->memcached_sync_count == DICT_TABLE_IN_DDL) { + /* We need to set the memcached sync back to 0, unblock + memcached operationse. */ + table->memcached_sync_count = 0; + } + row_mysql_unlock_data_dictionary(trx); dict_stats_update(table, DICT_STATS_EMPTY_TABLE); @@ -4702,6 +4731,9 @@ row_rename_table_for_mysql( " is replaced\n" "InnoDB: with raw, and innodb_force_... is removed.\n", stderr); + if(srv_force_recovery) { + err = DB_READ_ONLY; + } goto funct_exit; } else if (row_mysql_is_system_table(new_name)) { @@ -4975,15 +5007,31 @@ row_rename_table_for_mysql( if (err != DB_SUCCESS && (table->space != 0)) { char* orig_name = table->name; + trx_t* trx_bg = trx_allocate_for_background(); + + /* If the first fts_rename fails, the trx would + be rolled back and committed, we can't use it any more, + so we have to start a new background trx here. */ + ut_a(trx_state_eq(trx, TRX_STATE_NOT_STARTED)); + trx_bg->op_info = "Revert the failing rename " + "for fts aux tables"; + trx_bg->dict_operation_lock_mode = RW_X_LATCH; + trx_start_for_ddl(trx_bg, TRX_DICT_OP_TABLE); /* If rename fails and table has its own tablespace, we need to call fts_rename_aux_tables again to revert the ibd file rename, which is not under the control of trx. Also notice the parent table name - in cache is not changed yet. */ + in cache is not changed yet. If the reverting fails, + the ibd data may be left in the new database, which + can be fixed only manually. */ table->name = const_cast(new_name); - fts_rename_aux_tables(table, old_name, trx); + fts_rename_aux_tables(table, old_name, trx_bg); table->name = orig_name; + + trx_bg->dict_operation_lock_mode = 0; + trx_commit_for_mysql(trx_bg); + trx_free_for_background(trx_bg); } } diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 09cf75c1050..359ae3f2c21 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -5320,25 +5320,40 @@ func_exit: return(value); } -/*******************************************************************//** -Get the last row. -@return current rec or NULL */ +/** Get the maximum and non-delete-marked record in an index. +@param[in] index index tree +@param[in,out] mtr mini-transaction (may be committed and restarted) +@return maximum record, page s-latched in mtr +@retval NULL if there are no records, or if all of them are delete-marked */ static const rec_t* -row_search_autoinc_get_rec( -/*=======================*/ - btr_pcur_t* pcur, /*!< in: the current cursor */ - mtr_t* mtr) /*!< in: mini transaction */ +row_search_get_max_rec( + dict_index_t* index, + mtr_t* mtr) { + btr_pcur_t pcur; + const rec_t* rec; + /* Open at the high/right end (false), and init cursor */ + btr_pcur_open_at_index_side( + false, index, BTR_SEARCH_LEAF, &pcur, true, 0, mtr); + do { - const rec_t* rec = btr_pcur_get_rec(pcur); + const page_t* page; + + page = btr_pcur_get_page(&pcur); + rec = page_find_rec_max_not_deleted(page); if (page_rec_is_user_rec(rec)) { - return(rec); + break; + } else { + rec = NULL; } - } while (btr_pcur_move_to_prev(pcur, mtr)); + btr_pcur_move_before_first_on_page(&pcur); + } while (btr_pcur_move_to_prev(&pcur, mtr)); - return(NULL); + btr_pcur_close(&pcur); + + return(rec); } /*******************************************************************//** @@ -5353,55 +5368,30 @@ row_search_max_autoinc( const char* col_name, /*!< in: name of autoinc column */ ib_uint64_t* value) /*!< out: AUTOINC value read */ { - ulint i; - ulint n_cols; - dict_field_t* dfield = NULL; + dict_field_t* dfield = dict_index_get_nth_field(index, 0); dberr_t error = DB_SUCCESS; - - n_cols = dict_index_get_n_ordering_defined_by_user(index); - - /* Search the index for the AUTOINC column name */ - for (i = 0; i < n_cols; ++i) { - dfield = dict_index_get_nth_field(index, i); - - if (strcmp(col_name, dfield->name) == 0) { - break; - } - } - *value = 0; - /* Must find the AUTOINC column name */ - if (i < n_cols && dfield) { + if (strcmp(col_name, dfield->name) != 0) { + error = DB_RECORD_NOT_FOUND; + } else { mtr_t mtr; - btr_pcur_t pcur; + const rec_t* rec; mtr_start(&mtr); - /* Open at the high/right end (false), and init cursor */ - btr_pcur_open_at_index_side( - false, index, BTR_SEARCH_LEAF, &pcur, true, 0, &mtr); + rec = row_search_get_max_rec(index, &mtr); - if (!page_is_empty(btr_pcur_get_page(&pcur))) { - const rec_t* rec; + if (rec != NULL) { + ibool unsigned_type = ( + dfield->col->prtype & DATA_UNSIGNED); - rec = row_search_autoinc_get_rec(&pcur, &mtr); - - if (rec != NULL) { - ibool unsigned_type = ( - dfield->col->prtype & DATA_UNSIGNED); - - *value = row_search_autoinc_read_column( - index, rec, i, - dfield->col->mtype, unsigned_type); - } + *value = row_search_autoinc_read_column( + index, rec, 0, + dfield->col->mtype, unsigned_type); } - btr_pcur_close(&pcur); - mtr_commit(&mtr); - } else { - error = DB_RECORD_NOT_FOUND; } return(error); diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 7e2f7a8a049..fc903852cba 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -378,8 +378,8 @@ UNIV_INTERN ulint srv_available_undo_logs = 0; /* Set the following to 0 if you want InnoDB to write messages on stderr on startup/shutdown. */ UNIV_INTERN ibool srv_print_verbose_log = TRUE; -UNIV_INTERN ibool srv_print_innodb_monitor = FALSE; -UNIV_INTERN ibool srv_print_innodb_lock_monitor = FALSE; +UNIV_INTERN my_bool srv_print_innodb_monitor = FALSE; +UNIV_INTERN my_bool srv_print_innodb_lock_monitor = FALSE; UNIV_INTERN ibool srv_print_innodb_tablespace_monitor = FALSE; UNIV_INTERN ibool srv_print_innodb_table_monitor = FALSE; diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 00604a896ca..387f793a763 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -218,7 +218,8 @@ srv_file_check_mode( /* Note: stat.rw_perm is only valid of files */ - if (stat.type == OS_FILE_TYPE_FILE) { + if (stat.type == OS_FILE_TYPE_FILE + || stat.type == OS_FILE_TYPE_BLOCK) { if (!stat.rw_perm) { ib_logf(IB_LOG_LEVEL_ERROR, @@ -1526,6 +1527,16 @@ innobase_start_or_create_for_mysql(void) # endif /* F_FULLFSYNC */ #endif /* HAVE_DARWIN_THREADS */ + ib_logf(IB_LOG_LEVEL_INFO, + "Using %s to ref count buffer pool pages", +#ifdef PAGE_ATOMIC_REF_COUNT + "atomics" +#else + "mutexes" +#endif /* PAGE_ATOMIC_REF_COUNT */ + ); + + if (sizeof(ulint) != sizeof(void*)) { ut_print_timestamp(stderr); fprintf(stderr, diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc index 90f16719e20..5ef8a02fb3f 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -1137,6 +1137,7 @@ sync_thread_add_level( case SYNC_RECV: case SYNC_FTS_BG_THREADS: case SYNC_WORK_QUEUE: + case SYNC_FTS_TOKENIZE: case SYNC_FTS_OPTIMIZE: case SYNC_FTS_CACHE: case SYNC_FTS_CACHE_INIT: diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 7a75c7b573a..43c1308b44d 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -562,6 +562,13 @@ trx_resurrect_insert( trx->no = TRX_ID_MAX; } + /* trx_start_low() is not called with resurrect, so need to initialize + start time here.*/ + if (trx->state == TRX_STATE_ACTIVE + || trx->state == TRX_STATE_PREPARED) { + trx->start_time = ut_time(); + } + if (undo->dict_operation) { trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); trx->table_id = undo->table_id; @@ -649,6 +656,13 @@ trx_resurrect_update( trx->no = TRX_ID_MAX; } + /* trx_start_low() is not called with resurrect, so need to initialize + start time here.*/ + if (trx->state == TRX_STATE_ACTIVE + || trx->state == TRX_STATE_PREPARED) { + trx->start_time = ut_time(); + } + if (undo->dict_operation) { trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); trx->table_id = undo->table_id; diff --git a/storage/oqgraph/CMakeLists.txt b/storage/oqgraph/CMakeLists.txt index 0c361e27707..151082469a9 100644 --- a/storage/oqgraph/CMakeLists.txt +++ b/storage/oqgraph/CMakeLists.txt @@ -16,12 +16,12 @@ ENDIF() INCLUDE_DIRECTORIES(${Judy_INCLUDE_DIR}) IF(MSVC) - # lp:756966 OQGRAPH on Win64 does not compile - IF (CMAKE_SIZEOF_VOID_P EQUAL 8) - SET(BOOST_OK 0) - ELSE() +# # lp:756966 OQGRAPH on Win64 does not compile +# IF (CMAKE_SIZEOF_VOID_P EQUAL 8) +# SET(BOOST_OK 0) +# ELSE() SET(BOOST_OK 1) - ENDIF() +# ENDIF() ELSE() # See if that works. On old gcc it'll fail because of -fno-rtti CHECK_CXX_SOURCE_COMPILES( @@ -38,6 +38,8 @@ IF(BOOST_OK) ADD_DEFINITIONS(-DHAVE_OQGRAPH) IF(MSVC) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc") + # Fix problem with judy not finding inttypes.h on Windows: + ADD_DEFINITIONS(-DJU_WIN) ELSE(MSVC) # Fix lp bug 1221555 with -fpermissive, so that errors in gcc 4.7 become warnings for the time being SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -fno-strict-aliasing -fpermissive") diff --git a/storage/oqgraph/README b/storage/oqgraph/README index c3ab9813393..b92601ec180 100644 --- a/storage/oqgraph/README +++ b/storage/oqgraph/README @@ -1,5 +1,5 @@ OQGraph storage engine v3 -Copyright (C) 2007-2013 Arjen G Lentz & Antony T Curtis for Open Query +Copyright (C) 2007-2014 Arjen G Lentz & Antony T Curtis for Open Query, & Andrew McDonnell The Open Query GRAPH engine (OQGRAPH) is a computation engine allowing hierarchies and more complex graph structures to be handled in a @@ -12,9 +12,22 @@ v3 implementation by Antony Curtis, Arjen Lentz, Andrew McDonnell For more information, documentation, support, enhancement engineering, see http://openquery.com/graph or contact graph@openquery.com - - INSTALLATION -OQGraph requires at least version 1.40.0 of the Boost library. To +OQGraph requires at least version 1.40.0 of the Boost Graph library. To obtain a copy of the Boost library, see http://www.boost.org/ +This can be obtained in Debian Wheezy by `apt-get install libboost-graph-dev` + +OQGraph requires libjudy - http://judy.sourceforge.net/ +This can be obtained in Debian Wheezy by `apt-get install libjudy-dev` + +BUILD (example) + +cd path/to/maria/source +mkdir build # use symlink to scratch +cd build +CONFIGURE="-DWITH_EXTRA_CHARSETS=complex -DWITH_PLUGIN_ARIA=1 -DWITH_READLINE=1 -DWITH_SSL=bundled -DWITH_MAX=1 -DWITH_EMBEDDED_SERVER=1" +cmake .. $CONFIGURE +make -j5 +mysql-test-run --suite oqgraph + diff --git a/storage/oqgraph/cmake/FindJudy.cmake b/storage/oqgraph/cmake/FindJudy.cmake index 45706a67b66..d9ecfdc4a4f 100644 --- a/storage/oqgraph/cmake/FindJudy.cmake +++ b/storage/oqgraph/cmake/FindJudy.cmake @@ -1,4 +1,18 @@ -# - Try to find Judy +# - Try to find Judy. +# +# Additionally, on Windows, this module reads hints about search locations from variables: +# JUDY_ROOT - Preferred installation prefix +# +# To build Judy on Windows: (Tested with judy-1.0.5) +# +# * Download the sources tarball from http://sourceforge.net/projects/judy/ +# * Extract the source +# * Win32: open the Visual Studio C++ Express 2010 command prompt and navigate to the src/ directory. +# Then execute: build.bat +# * Win64: open the Windows SDK 7.1 Command Prompt and navigate to the src/ directory +# Then execute: build.bat +# * Run the mariadb build with JUDY_ROOT=path\to\judy +# # Once done this will define # # Judy_FOUND - system has Judy @@ -6,17 +20,37 @@ # Judy_LIBRARIES - Link these to use Judy # Judy_DEFINITIONS - Compiler switches required for using Judy -IF (Judy_INCLUDE_DIR AND Judy_LIBRARIES) - SET(Judy_FIND_QUIETLY TRUE) -ENDIF (Judy_INCLUDE_DIR AND Judy_LIBRARIES) +IF(MSVC) + # For now, assume Judy built according to the above instructions + if (NOT "$ENV{JUDY_ROOT}" STREQUAL "") + # Avoid passing backslashes to _Boost_FIND_LIBRARY due to macro re-parsing. + string(REPLACE "\\" "/" Judy_INCLUDE_DIR_search $ENV{JUDY_ROOT}/src) + string(REPLACE "\\" "/" Judy_LIBRARIES_search $ENV{JUDY_ROOT}/src) + endif() +ELSE(MSVC) + IF (Judy_INCLUDE_DIR AND Judy_LIBRARIES) + SET(Judy_FIND_QUIETLY TRUE) + ENDIF (Judy_INCLUDE_DIR AND Judy_LIBRARIES) +ENDIF(MSVC) -FIND_PATH(Judy_INCLUDE_DIR Judy.h) -FIND_LIBRARY(Judy_LIBRARIES NAMES Judy) +FIND_PATH(Judy_INCLUDE_DIR Judy.h PATHS ${Judy_INCLUDE_DIR_search}) +FIND_LIBRARY(Judy_LIBRARIES Judy PATHS ${Judy_LIBRARIES_search}) IF (Judy_INCLUDE_DIR AND Judy_LIBRARIES) - SET(Judy_FOUND TRUE) + SET(Judy_FOUND TRUE) ELSE (Judy_INCLUDE_DIR AND Judy_LIBRARIES) - SET(Judy_FOUND FALSE) + SET(Judy_FOUND FALSE) + if (MSVC) + MESSAGE(STATUS "How to build Judy on Windows:") + MESSAGE(STATUS "1. Download the source tarball from http://sourceforge.net/projects/judy/") + IF (CMAKE_SIZEOF_VOID_P EQUAL 8) + MESSAGE(STATUS "2. Extract the source, open the Visual Studio command prompt and navigate to the src/ directory.") + ELSE (CMAKE_SIZEOF_VOID_P EQUAL 8) + MESSAGE(STATUS "2. Extract the source, open the Windows SDK 7.1 Command Prompt and navigate to the src/ directory.") + ENDIF (CMAKE_SIZEOF_VOID_P EQUAL 8) + MESSAGE(STATUS "3. Execute the command: 'build'") + MESSAGE(STATUS "4. Rerun this cmake with the environment variable: 'set JUDY_ROOT=x:\\path\\to\\judy'") + endif(MSVC) ENDIF (Judy_INCLUDE_DIR AND Judy_LIBRARIES) IF (Judy_FOUND) diff --git a/storage/oqgraph/graphcore.cc b/storage/oqgraph/graphcore.cc index 96be1b450f3..de575c9da65 100644 --- a/storage/oqgraph/graphcore.cc +++ b/storage/oqgraph/graphcore.cc @@ -1122,7 +1122,12 @@ int edges_cursor::fetch_row(const row &row_info, row &result, // but origid and destid can be -1 indicating no such record, NULL? but oqgraph3::vertex_id // seems to resolve to VertexID (unsigned) in row // in any case we should check for errors (-1) in origid... because all edges have at least one vertex by definition - assert( ! ((size_t)orig == (size_t)-1 && (size_t)dest == (size_t)-1)); // indicates we havent handle a HA_ERR_RECORD_DELETED somewhere + if (orig == (oqgraph3::vertex_id)-1 && dest == (oqgraph3::vertex_id)-1) { + // Select * from graph; -- when backing store is empty (bug MDEV-5891) + return oqgraph::NO_MORE_DATA; + } + // assert( ! ((size_t)orig == (size_t)-1 && (size_t)dest == (size_t)-1)); + // indicates we havent handle a HA_ERR_RECORD_DELETED somewhere result.orig= orig; result.dest= dest; diff --git a/storage/oqgraph/ha_oqgraph.cc b/storage/oqgraph/ha_oqgraph.cc index 650be75ceda..aa7e5c5a322 100644 --- a/storage/oqgraph/ha_oqgraph.cc +++ b/storage/oqgraph/ha_oqgraph.cc @@ -557,9 +557,11 @@ int ha_oqgraph::open(const char *name, int mode, uint test_if_locked) size_t tlen= strlen(options->table_name); size_t plen= (int)(p - name) + tlen + 1; - share->path.str= (char*)alloc_root(&share->mem_root, plen); + share->path.str= (char*)alloc_root(&share->mem_root, plen + 1); // MDEV-5996 space for trailing zero + // it seems there was a misunderstanding of why there is a separate length field in the String object strmov(strnmov(share->path.str, name, (int)(p - name) + 1), options->table_name); + share->path.str[plen] = 0; // MDEV-5996 Make sure the pointer is zero terminated. I really think this needs refactoring, soon... share->normalized_path.str= share->path.str; share->path.length= share->normalized_path.length= plen; diff --git a/storage/oqgraph/mysql-test/oqgraph/basic.result b/storage/oqgraph/mysql-test/oqgraph/general-Aria.result similarity index 99% rename from storage/oqgraph/mysql-test/oqgraph/basic.result rename to storage/oqgraph/mysql-test/oqgraph/general-Aria.result index 84943d05070..f0c5b51a266 100644 --- a/storage/oqgraph/mysql-test/oqgraph/basic.result +++ b/storage/oqgraph/mysql-test/oqgraph/general-Aria.result @@ -1,12 +1,13 @@ DROP TABLE IF EXISTS graph_base; DROP TABLE IF EXISTS graph; DROP TABLE IF EXISTS graph2; +Performing OQGraph General test suite for ENGINE=Aria CREATE TABLE graph_base ( from_id INT UNSIGNED NOT NULL, to_id INT UNSIGNED NOT NULL, PRIMARY KEY (from_id,to_id), INDEX (to_id) -) ENGINE=MyISAM; +) ENGINE= Aria ; CREATE TABLE graph ( latch VARCHAR(32) NULL, origid BIGINT UNSIGNED NULL, @@ -17,6 +18,8 @@ linkid BIGINT UNSIGNED NULL, KEY (latch, origid, destid) USING HASH, KEY (latch, destid, origid) USING HASH ) ENGINE=OQGRAPH DATA_TABLE='graph_base' ORIGID='from_id', DESTID='to_id'; +select * from graph; +latch origid destid weight seq linkid INSERT INTO graph_base(from_id, to_id) VALUES (1,2), (2,1); INSERT INTO graph_base(from_id, to_id) VALUES (1,3), (3,1); INSERT INTO graph_base(from_id, to_id) VALUES (3,4), (4,3); diff --git a/storage/oqgraph/mysql-test/oqgraph/general-Aria.test b/storage/oqgraph/mysql-test/oqgraph/general-Aria.test new file mode 100644 index 00000000000..f2a0146fb75 --- /dev/null +++ b/storage/oqgraph/mysql-test/oqgraph/general-Aria.test @@ -0,0 +1,3 @@ +# This is a maintainer generated file. Generated at Wednesday 5 February 22:26:12 CST 2014. +--let $oqgraph_use_table_type= Aria +--source general.inc diff --git a/storage/oqgraph/mysql-test/oqgraph/general-MyISAM.result b/storage/oqgraph/mysql-test/oqgraph/general-MyISAM.result new file mode 100644 index 00000000000..c08e0c295d2 --- /dev/null +++ b/storage/oqgraph/mysql-test/oqgraph/general-MyISAM.result @@ -0,0 +1,1441 @@ +DROP TABLE IF EXISTS graph_base; +DROP TABLE IF EXISTS graph; +DROP TABLE IF EXISTS graph2; +Performing OQGraph General test suite for ENGINE=MyISAM +CREATE TABLE graph_base ( +from_id INT UNSIGNED NOT NULL, +to_id INT UNSIGNED NOT NULL, +PRIMARY KEY (from_id,to_id), +INDEX (to_id) +) ENGINE= MyISAM ; +CREATE TABLE graph ( +latch VARCHAR(32) NULL, +origid BIGINT UNSIGNED NULL, +destid BIGINT UNSIGNED NULL, +weight DOUBLE NULL, +seq BIGINT UNSIGNED NULL, +linkid BIGINT UNSIGNED NULL, +KEY (latch, origid, destid) USING HASH, +KEY (latch, destid, origid) USING HASH +) ENGINE=OQGRAPH DATA_TABLE='graph_base' ORIGID='from_id', DESTID='to_id'; +select * from graph; +latch origid destid weight seq linkid +INSERT INTO graph_base(from_id, to_id) VALUES (1,2), (2,1); +INSERT INTO graph_base(from_id, to_id) VALUES (1,3), (3,1); +INSERT INTO graph_base(from_id, to_id) VALUES (3,4), (4,3); +INSERT INTO graph_base(from_id, to_id) VALUES (5,6), (6,5); +INSERT INTO graph_base(from_id, to_id) VALUES (5,7); +INSERT INTO graph_base(from_id, to_id) VALUES (9,9); +INSERT INTO graph_base(from_id, to_id) VALUES (10,11); +INSERT INTO graph_base(from_id, to_id) VALUES (11,12); +INSERT INTO graph_base(from_id, to_id) VALUES (12,10); +# Return all edges +SELECT * FROM graph; +latch origid destid weight seq linkid +NULL 1 2 1 NULL NULL +NULL 2 1 1 NULL NULL +NULL 1 3 1 NULL NULL +NULL 3 1 1 NULL NULL +NULL 3 4 1 NULL NULL +NULL 4 3 1 NULL NULL +NULL 5 6 1 NULL NULL +NULL 6 5 1 NULL NULL +NULL 5 7 1 NULL NULL +NULL 9 9 1 NULL NULL +NULL 10 11 1 NULL NULL +NULL 11 12 1 NULL NULL +NULL 12 10 1 NULL NULL +# Currently count should be 13 +SELECT count(*) FROM graph; +count(*) +13 +# Return all edges when latch is NULL - this is different to latch='' and same as no where clause +SELECT * FROM graph where latch is NULL; +latch origid destid weight seq linkid +NULL 1 2 1 NULL NULL +NULL 2 1 1 NULL NULL +NULL 1 3 1 NULL NULL +NULL 3 1 1 NULL NULL +NULL 3 4 1 NULL NULL +NULL 4 3 1 NULL NULL +NULL 5 6 1 NULL NULL +NULL 6 5 1 NULL NULL +NULL 5 7 1 NULL NULL +NULL 9 9 1 NULL NULL +NULL 10 11 1 NULL NULL +NULL 11 12 1 NULL NULL +NULL 12 10 1 NULL NULL +# Return all vertices, and subsets of vertices +SELECT * FROM graph where latch=''; +latch origid destid weight seq linkid + NULL NULL NULL NULL 1 + NULL NULL NULL NULL 2 + NULL NULL NULL NULL 3 + NULL NULL NULL NULL 4 + NULL NULL NULL NULL 5 + NULL NULL NULL NULL 6 + NULL NULL NULL NULL 7 + NULL NULL NULL NULL 9 + NULL NULL NULL NULL 10 + NULL NULL NULL NULL 11 + NULL NULL NULL NULL 12 +SELECT * FROM graph where latch='0'; +latch origid destid weight seq linkid +0 NULL NULL NULL NULL 1 +0 NULL NULL NULL NULL 2 +0 NULL NULL NULL NULL 3 +0 NULL NULL NULL NULL 4 +0 NULL NULL NULL NULL 5 +0 NULL NULL NULL NULL 6 +0 NULL NULL NULL NULL 7 +0 NULL NULL NULL NULL 9 +0 NULL NULL NULL NULL 10 +0 NULL NULL NULL NULL 11 +0 NULL NULL NULL NULL 12 +# Currently count should be 11 +SELECT count(*) FROM graph where latch=''; +count(*) +11 +SELECT * FROM graph where latch='' and linkid = 2; +latch origid destid weight seq linkid + NULL NULL NULL NULL 2 +SELECT * FROM graph where latch='' and (linkid > 2 and linkid < 6); +latch origid destid weight seq linkid + NULL NULL NULL NULL 3 + NULL NULL NULL NULL 4 + NULL NULL NULL NULL 5 +SELECT * FROM graph where latch='' and linkid = NULL; +latch origid destid weight seq linkid +SELECT * FROM graph where latch='' and linkid = 666; +latch origid destid weight seq linkid +SELECT origid as `from`, linkid as `to` FROM graph where latch='' and origid = 1; +from to +1 3 +1 2 +SELECT origid as `from`, linkid as `to` FROM graph where latch='' and origid = 2; +from to +2 1 +SELECT origid as `from`, linkid as `to` FROM graph where latch='' and origid = 4; +from to +4 3 +SELECT origid as `from`, linkid as `to` FROM graph where latch='' and origid = 9; +from to +9 9 +SELECT origid as `from`, linkid as `to` FROM graph where latch='' and origid = 10; +from to +10 11 +SELECT origid as `from`, linkid as `to` FROM graph where latch='' and origid = NULL; +from to +SELECT origid as `from`, linkid as `to` FROM graph where latch='' and origid = 666; +from to +SELECT linkid as `from`, destid as `to` FROM graph where latch='' and destid = 1; +from to +3 1 +2 1 +SELECT linkid as `from`, destid as `to` FROM graph where latch='' and destid = 2; +from to +1 2 +SELECT linkid as `from`, destid as `to` FROM graph where latch='' and destid = 4; +from to +3 4 +SELECT linkid as `from`, destid as `to` FROM graph where latch='' and destid = 9; +from to +9 9 +SELECT linkid as `from`, destid as `to` FROM graph where latch='' and destid = 10; +from to +12 10 +SELECT linkid as `from`, destid as `to` FROM graph where latch='' and destid = NULL; +from to +SELECT linkid as `from`, destid as `to` FROM graph where latch='' and destid = 666; +from to +SELECT * FROM graph where latch='0'; +latch origid destid weight seq linkid +0 NULL NULL NULL NULL 1 +0 NULL NULL NULL NULL 2 +0 NULL NULL NULL NULL 3 +0 NULL NULL NULL NULL 4 +0 NULL NULL NULL NULL 5 +0 NULL NULL NULL NULL 6 +0 NULL NULL NULL NULL 7 +0 NULL NULL NULL NULL 9 +0 NULL NULL NULL NULL 10 +0 NULL NULL NULL NULL 11 +0 NULL NULL NULL NULL 12 +SELECT count(*) FROM graph where latch='0'; +count(*) +11 +SELECT * FROM graph where latch='0' and linkid = 2; +latch origid destid weight seq linkid +0 NULL NULL NULL NULL 2 +SELECT * FROM graph where latch='0' and (linkid > 2 and linkid < 6); +latch origid destid weight seq linkid +0 NULL NULL NULL NULL 3 +0 NULL NULL NULL NULL 4 +0 NULL NULL NULL NULL 5 +SELECT origid as `from`, linkid as `to` FROM graph where latch='0' and origid = 1; +from to +1 3 +1 2 +SELECT origid as `from`, linkid as `to` FROM graph where latch='0' and origid = 2; +from to +2 1 +SELECT origid as `from`, linkid as `to` FROM graph where latch='0' and origid = 4; +from to +4 3 +SELECT origid as `from`, linkid as `to` FROM graph where latch='0' and origid = 9; +from to +9 9 +SELECT origid as `from`, linkid as `to` FROM graph where latch='0' and origid = 10; +from to +10 11 +SELECT linkid as `from`, destid as `to` FROM graph where latch='0' and destid = 1; +from to +3 1 +2 1 +SELECT linkid as `from`, destid as `to` FROM graph where latch='0' and destid = 2; +from to +1 2 +SELECT linkid as `from`, destid as `to` FROM graph where latch='0' and destid = 4; +from to +3 4 +SELECT linkid as `from`, destid as `to` FROM graph where latch='0' and destid = 9; +from to +9 9 +SELECT linkid as `from`, destid as `to` FROM graph where latch='0' and destid = 10; +from to +12 10 +# Breadth-first search tests +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 1; +latch origid destid weight seq linkid +breadth_first 1 NULL 2 4 4 +breadth_first 1 NULL 1 3 3 +breadth_first 1 NULL 1 2 2 +breadth_first 1 NULL 0 1 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 2; +latch origid destid weight seq linkid +breadth_first 2 NULL 3 4 4 +breadth_first 2 NULL 2 3 3 +breadth_first 2 NULL 1 2 1 +breadth_first 2 NULL 0 1 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 3; +latch origid destid weight seq linkid +breadth_first 3 NULL 2 4 2 +breadth_first 3 NULL 1 3 4 +breadth_first 3 NULL 1 2 1 +breadth_first 3 NULL 0 1 3 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 4; +latch origid destid weight seq linkid +breadth_first 4 NULL 3 4 2 +breadth_first 4 NULL 2 3 1 +breadth_first 4 NULL 1 2 3 +breadth_first 4 NULL 0 1 4 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 5; +latch origid destid weight seq linkid +breadth_first 5 NULL 1 3 7 +breadth_first 5 NULL 1 2 6 +breadth_first 5 NULL 0 1 5 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 6; +latch origid destid weight seq linkid +breadth_first 6 NULL 2 3 7 +breadth_first 6 NULL 1 2 5 +breadth_first 6 NULL 0 1 6 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 7; +latch origid destid weight seq linkid +breadth_first 7 NULL 0 1 7 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 9; +latch origid destid weight seq linkid +breadth_first 9 NULL 0 1 9 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 10; +latch origid destid weight seq linkid +breadth_first 10 NULL 2 3 12 +breadth_first 10 NULL 1 2 11 +breadth_first 10 NULL 0 1 10 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 11; +latch origid destid weight seq linkid +breadth_first 11 NULL 2 3 10 +breadth_first 11 NULL 1 2 12 +breadth_first 11 NULL 0 1 11 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 12; +latch origid destid weight seq linkid +breadth_first 12 NULL 2 3 11 +breadth_first 12 NULL 1 2 10 +breadth_first 12 NULL 0 1 12 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 666; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 1 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 1 NULL 1 3 3 +breadth_first 1 NULL 1 2 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 2 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 2 NULL 1 2 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 3 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 3 NULL 1 3 4 +breadth_first 3 NULL 1 2 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 4 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 4 NULL 1 2 3 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 5 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 5 NULL 1 3 7 +breadth_first 5 NULL 1 2 6 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 6 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 6 NULL 1 2 5 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 7 AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 8 AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 9 AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 10 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 10 NULL 1 2 11 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 11 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 11 NULL 1 2 12 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 12 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 12 NULL 1 2 10 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 1 AND weight = 1; +count(*) +2 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 2 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 3 AND weight = 1; +count(*) +2 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 4 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 5 AND weight = 1; +count(*) +2 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 6 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 7 AND weight = 1; +count(*) +0 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 8 AND weight = 1; +count(*) +0 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 9 AND weight = 1; +count(*) +0 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 10 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 11 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 12 AND weight = 1; +count(*) +1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 1 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 1 NULL 2 4 4 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 2 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 2 NULL 2 3 3 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 3 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 3 NULL 2 4 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 4 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 4 NULL 2 3 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 5 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 6 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 6 NULL 2 3 7 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 7 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 8 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 9 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 10 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 10 NULL 2 3 12 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 11 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 11 NULL 2 3 10 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 12 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 12 NULL 2 3 11 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 1 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 2 AND weight = 3; +latch origid destid weight seq linkid +breadth_first 2 NULL 3 4 4 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 3 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 4 AND weight = 3; +latch origid destid weight seq linkid +breadth_first 4 NULL 3 4 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 5 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 6 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 7 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 8 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 9 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 10 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 11 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 12 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 1 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 1 NULL 2 4 4 +breadth_first 1 NULL 1 3 3 +breadth_first 1 NULL 1 2 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 2 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 2 NULL 2 3 3 +breadth_first 2 NULL 1 2 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 3 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 3 NULL 2 4 2 +breadth_first 3 NULL 1 3 4 +breadth_first 3 NULL 1 2 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 4 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 4 NULL 2 3 1 +breadth_first 4 NULL 1 2 3 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 5 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 5 NULL 1 3 7 +breadth_first 5 NULL 1 2 6 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 6 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 6 NULL 2 3 7 +breadth_first 6 NULL 1 2 5 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 7 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 8 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 9 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 10 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 10 NULL 2 3 12 +breadth_first 10 NULL 1 2 11 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 11 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 11 NULL 2 3 10 +breadth_first 11 NULL 1 2 12 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 12 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 12 NULL 2 3 11 +breadth_first 12 NULL 1 2 10 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 1; +latch origid destid weight seq linkid +breadth_first NULL 1 2 4 4 +breadth_first NULL 1 1 3 3 +breadth_first NULL 1 1 2 2 +breadth_first NULL 1 0 1 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 2; +latch origid destid weight seq linkid +breadth_first NULL 2 3 4 4 +breadth_first NULL 2 2 3 3 +breadth_first NULL 2 1 2 1 +breadth_first NULL 2 0 1 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 3; +latch origid destid weight seq linkid +breadth_first NULL 3 2 4 2 +breadth_first NULL 3 1 3 4 +breadth_first NULL 3 1 2 1 +breadth_first NULL 3 0 1 3 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 4; +latch origid destid weight seq linkid +breadth_first NULL 4 3 4 2 +breadth_first NULL 4 2 3 1 +breadth_first NULL 4 1 2 3 +breadth_first NULL 4 0 1 4 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 5; +latch origid destid weight seq linkid +breadth_first NULL 5 1 3 7 +breadth_first NULL 5 1 2 6 +breadth_first NULL 5 0 1 5 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 6; +latch origid destid weight seq linkid +breadth_first NULL 6 2 3 7 +breadth_first NULL 6 1 2 5 +breadth_first NULL 6 0 1 6 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 7; +latch origid destid weight seq linkid +breadth_first NULL 7 0 1 7 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 9; +latch origid destid weight seq linkid +breadth_first NULL 9 0 1 9 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 10; +latch origid destid weight seq linkid +breadth_first NULL 10 2 3 12 +breadth_first NULL 10 1 2 11 +breadth_first NULL 10 0 1 10 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 11; +latch origid destid weight seq linkid +breadth_first NULL 11 2 3 10 +breadth_first NULL 11 1 2 12 +breadth_first NULL 11 0 1 11 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 12; +latch origid destid weight seq linkid +breadth_first NULL 12 2 3 11 +breadth_first NULL 12 1 2 10 +breadth_first NULL 12 0 1 12 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 1 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 1 1 3 3 +breadth_first NULL 1 1 2 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 2 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 2 1 2 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 3 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 3 1 3 4 +breadth_first NULL 3 1 2 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 4 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 4 1 2 3 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 5 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 5 1 3 7 +breadth_first NULL 5 1 2 6 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 6 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 6 1 2 5 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 7 and weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 8 and weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 9 and weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 10 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 10 1 2 11 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 11 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 11 1 2 12 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 12 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 12 1 2 10 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 1 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 1 2 4 4 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 2 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 2 2 3 3 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 3 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 3 2 4 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 4 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 4 2 3 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 5 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 6 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 6 2 3 7 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 7 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 8 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 9 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 10 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 10 2 3 12 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 11 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 11 2 3 10 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 12 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 12 2 3 11 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 1 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 2 and weight = 3; +latch origid destid weight seq linkid +breadth_first NULL 2 3 4 4 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 3 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 4 and weight = 3; +latch origid destid weight seq linkid +breadth_first NULL 4 3 4 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 5 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 6 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 7 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 8 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 9 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 10 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 11 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 12 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = NULL; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = NULL; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first'; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 1; +latch origid destid weight seq linkid +2 1 NULL 2 4 4 +2 1 NULL 1 3 3 +2 1 NULL 1 2 2 +2 1 NULL 0 1 1 +SELECT * FROM graph WHERE latch = '2' AND origid = 2; +latch origid destid weight seq linkid +2 2 NULL 3 4 4 +2 2 NULL 2 3 3 +2 2 NULL 1 2 1 +2 2 NULL 0 1 2 +SELECT * FROM graph WHERE latch = '2' AND origid = 3; +latch origid destid weight seq linkid +2 3 NULL 2 4 2 +2 3 NULL 1 3 4 +2 3 NULL 1 2 1 +2 3 NULL 0 1 3 +SELECT * FROM graph WHERE latch = '2' AND origid = 4; +latch origid destid weight seq linkid +2 4 NULL 3 4 2 +2 4 NULL 2 3 1 +2 4 NULL 1 2 3 +2 4 NULL 0 1 4 +SELECT * FROM graph WHERE latch = '2' AND origid = 5; +latch origid destid weight seq linkid +2 5 NULL 1 3 7 +2 5 NULL 1 2 6 +2 5 NULL 0 1 5 +SELECT * FROM graph WHERE latch = '2' AND origid = 6; +latch origid destid weight seq linkid +2 6 NULL 2 3 7 +2 6 NULL 1 2 5 +2 6 NULL 0 1 6 +SELECT * FROM graph WHERE latch = '2' AND origid = 7; +latch origid destid weight seq linkid +2 7 NULL 0 1 7 +SELECT * FROM graph WHERE latch = '2' AND origid = 8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 9; +latch origid destid weight seq linkid +2 9 NULL 0 1 9 +SELECT * FROM graph WHERE latch = '2' AND origid = 10; +latch origid destid weight seq linkid +2 10 NULL 2 3 12 +2 10 NULL 1 2 11 +2 10 NULL 0 1 10 +SELECT * FROM graph WHERE latch = '2' AND origid = 11; +latch origid destid weight seq linkid +2 11 NULL 2 3 10 +2 11 NULL 1 2 12 +2 11 NULL 0 1 11 +SELECT * FROM graph WHERE latch = '2' AND origid = 12; +latch origid destid weight seq linkid +2 12 NULL 2 3 11 +2 12 NULL 1 2 10 +2 12 NULL 0 1 12 +SELECT * FROM graph WHERE latch = '2' AND origid = 666; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 1 AND weight = 1; +latch origid destid weight seq linkid +2 1 NULL 1 3 3 +2 1 NULL 1 2 2 +SELECT * FROM graph WHERE latch = '2' AND origid = 2 AND weight = 1; +latch origid destid weight seq linkid +2 2 NULL 1 2 1 +SELECT * FROM graph WHERE latch = '2' AND origid = 3 AND weight = 1; +latch origid destid weight seq linkid +2 3 NULL 1 3 4 +2 3 NULL 1 2 1 +SELECT * FROM graph WHERE latch = '2' AND origid = 4 AND weight = 1; +latch origid destid weight seq linkid +2 4 NULL 1 2 3 +SELECT * FROM graph WHERE latch = '2' AND origid = 5 AND weight = 1; +latch origid destid weight seq linkid +2 5 NULL 1 3 7 +2 5 NULL 1 2 6 +SELECT * FROM graph WHERE latch = '2' AND origid = 6 AND weight = 1; +latch origid destid weight seq linkid +2 6 NULL 1 2 5 +SELECT * FROM graph WHERE latch = '2' AND origid = 7 AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 8 AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 9 AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 10 AND weight = 1; +latch origid destid weight seq linkid +2 10 NULL 1 2 11 +SELECT * FROM graph WHERE latch = '2' AND origid = 11 AND weight = 1; +latch origid destid weight seq linkid +2 11 NULL 1 2 12 +SELECT * FROM graph WHERE latch = '2' AND origid = 12 AND weight = 1; +latch origid destid weight seq linkid +2 12 NULL 1 2 10 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 1 AND weight = 1; +count(*) +2 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 2 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 3 AND weight = 1; +count(*) +2 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 4 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 5 AND weight = 1; +count(*) +2 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 6 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 7 AND weight = 1; +count(*) +0 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 8 AND weight = 1; +count(*) +0 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 9 AND weight = 1; +count(*) +0 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 10 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 11 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 12 AND weight = 1; +count(*) +1 +SELECT * FROM graph WHERE latch = '2' AND origid = 1 AND weight = 2; +latch origid destid weight seq linkid +2 1 NULL 2 4 4 +SELECT * FROM graph WHERE latch = '2' AND origid = 2 AND weight = 2; +latch origid destid weight seq linkid +2 2 NULL 2 3 3 +SELECT * FROM graph WHERE latch = '2' AND origid = 3 AND weight = 2; +latch origid destid weight seq linkid +2 3 NULL 2 4 2 +SELECT * FROM graph WHERE latch = '2' AND origid = 4 AND weight = 2; +latch origid destid weight seq linkid +2 4 NULL 2 3 1 +SELECT * FROM graph WHERE latch = '2' AND origid = 5 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 6 AND weight = 2; +latch origid destid weight seq linkid +2 6 NULL 2 3 7 +SELECT * FROM graph WHERE latch = '2' AND origid = 7 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 8 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 9 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 10 AND weight = 2; +latch origid destid weight seq linkid +2 10 NULL 2 3 12 +SELECT * FROM graph WHERE latch = '2' AND origid = 11 AND weight = 2; +latch origid destid weight seq linkid +2 11 NULL 2 3 10 +SELECT * FROM graph WHERE latch = '2' AND origid = 12 AND weight = 2; +latch origid destid weight seq linkid +2 12 NULL 2 3 11 +SELECT * FROM graph WHERE latch = '2' AND origid = 1 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 2 AND weight = 3; +latch origid destid weight seq linkid +2 2 NULL 3 4 4 +SELECT * FROM graph WHERE latch = '2' AND origid = 3 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 4 AND weight = 3; +latch origid destid weight seq linkid +2 4 NULL 3 4 2 +SELECT * FROM graph WHERE latch = '2' AND origid = 5 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 6 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 7 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 8 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 9 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 10 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 11 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 12 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 1 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 1 NULL 2 4 4 +2 1 NULL 1 3 3 +2 1 NULL 1 2 2 +SELECT * FROM graph WHERE latch = '2' AND origid = 2 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 2 NULL 2 3 3 +2 2 NULL 1 2 1 +SELECT * FROM graph WHERE latch = '2' AND origid = 3 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 3 NULL 2 4 2 +2 3 NULL 1 3 4 +2 3 NULL 1 2 1 +SELECT * FROM graph WHERE latch = '2' AND origid = 4 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 4 NULL 2 3 1 +2 4 NULL 1 2 3 +SELECT * FROM graph WHERE latch = '2' AND origid = 5 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 5 NULL 1 3 7 +2 5 NULL 1 2 6 +SELECT * FROM graph WHERE latch = '2' AND origid = 6 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 6 NULL 2 3 7 +2 6 NULL 1 2 5 +SELECT * FROM graph WHERE latch = '2' AND origid = 7 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 8 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 9 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 10 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 10 NULL 2 3 12 +2 10 NULL 1 2 11 +SELECT * FROM graph WHERE latch = '2' AND origid = 11 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 11 NULL 2 3 10 +2 11 NULL 1 2 12 +SELECT * FROM graph WHERE latch = '2' AND origid = 12 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 12 NULL 2 3 11 +2 12 NULL 1 2 10 +SELECT * FROM graph WHERE latch = '2' AND destid = 1; +latch origid destid weight seq linkid +2 NULL 1 2 4 4 +2 NULL 1 1 3 3 +2 NULL 1 1 2 2 +2 NULL 1 0 1 1 +SELECT * FROM graph WHERE latch = '2' AND destid = 2; +latch origid destid weight seq linkid +2 NULL 2 3 4 4 +2 NULL 2 2 3 3 +2 NULL 2 1 2 1 +2 NULL 2 0 1 2 +SELECT * FROM graph WHERE latch = '2' AND destid = 3; +latch origid destid weight seq linkid +2 NULL 3 2 4 2 +2 NULL 3 1 3 4 +2 NULL 3 1 2 1 +2 NULL 3 0 1 3 +SELECT * FROM graph WHERE latch = '2' AND destid = 4; +latch origid destid weight seq linkid +2 NULL 4 3 4 2 +2 NULL 4 2 3 1 +2 NULL 4 1 2 3 +2 NULL 4 0 1 4 +SELECT * FROM graph WHERE latch = '2' AND destid = 5; +latch origid destid weight seq linkid +2 NULL 5 1 3 7 +2 NULL 5 1 2 6 +2 NULL 5 0 1 5 +SELECT * FROM graph WHERE latch = '2' AND destid = 6; +latch origid destid weight seq linkid +2 NULL 6 2 3 7 +2 NULL 6 1 2 5 +2 NULL 6 0 1 6 +SELECT * FROM graph WHERE latch = '2' AND destid = 7; +latch origid destid weight seq linkid +2 NULL 7 0 1 7 +SELECT * FROM graph WHERE latch = '2' AND destid = 8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 9; +latch origid destid weight seq linkid +2 NULL 9 0 1 9 +SELECT * FROM graph WHERE latch = '2' AND destid = 10; +latch origid destid weight seq linkid +2 NULL 10 2 3 12 +2 NULL 10 1 2 11 +2 NULL 10 0 1 10 +SELECT * FROM graph WHERE latch = '2' AND destid = 11; +latch origid destid weight seq linkid +2 NULL 11 2 3 10 +2 NULL 11 1 2 12 +2 NULL 11 0 1 11 +SELECT * FROM graph WHERE latch = '2' AND destid = 12; +latch origid destid weight seq linkid +2 NULL 12 2 3 11 +2 NULL 12 1 2 10 +2 NULL 12 0 1 12 +SELECT * FROM graph WHERE latch = '2' AND destid = 1 and weight = 1; +latch origid destid weight seq linkid +2 NULL 1 1 3 3 +2 NULL 1 1 2 2 +SELECT * FROM graph WHERE latch = '2' AND destid = 2 and weight = 1; +latch origid destid weight seq linkid +2 NULL 2 1 2 1 +SELECT * FROM graph WHERE latch = '2' AND destid = 3 and weight = 1; +latch origid destid weight seq linkid +2 NULL 3 1 3 4 +2 NULL 3 1 2 1 +SELECT * FROM graph WHERE latch = '2' AND destid = 4 and weight = 1; +latch origid destid weight seq linkid +2 NULL 4 1 2 3 +SELECT * FROM graph WHERE latch = '2' AND destid = 5 and weight = 1; +latch origid destid weight seq linkid +2 NULL 5 1 3 7 +2 NULL 5 1 2 6 +SELECT * FROM graph WHERE latch = '2' AND destid = 6 and weight = 1; +latch origid destid weight seq linkid +2 NULL 6 1 2 5 +SELECT * FROM graph WHERE latch = '2' AND destid = 7 and weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 8 and weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 9 and weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 10 and weight = 1; +latch origid destid weight seq linkid +2 NULL 10 1 2 11 +SELECT * FROM graph WHERE latch = '2' AND destid = 11 and weight = 1; +latch origid destid weight seq linkid +2 NULL 11 1 2 12 +SELECT * FROM graph WHERE latch = '2' AND destid = 12 and weight = 1; +latch origid destid weight seq linkid +2 NULL 12 1 2 10 +SELECT * FROM graph WHERE latch = '2' AND destid = 1 and weight = 2; +latch origid destid weight seq linkid +2 NULL 1 2 4 4 +SELECT * FROM graph WHERE latch = '2' AND destid = 2 and weight = 2; +latch origid destid weight seq linkid +2 NULL 2 2 3 3 +SELECT * FROM graph WHERE latch = '2' AND destid = 3 and weight = 2; +latch origid destid weight seq linkid +2 NULL 3 2 4 2 +SELECT * FROM graph WHERE latch = '2' AND destid = 4 and weight = 2; +latch origid destid weight seq linkid +2 NULL 4 2 3 1 +SELECT * FROM graph WHERE latch = '2' AND destid = 5 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 6 and weight = 2; +latch origid destid weight seq linkid +2 NULL 6 2 3 7 +SELECT * FROM graph WHERE latch = '2' AND destid = 7 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 8 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 9 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 10 and weight = 2; +latch origid destid weight seq linkid +2 NULL 10 2 3 12 +SELECT * FROM graph WHERE latch = '2' AND destid = 11 and weight = 2; +latch origid destid weight seq linkid +2 NULL 11 2 3 10 +SELECT * FROM graph WHERE latch = '2' AND destid = 12 and weight = 2; +latch origid destid weight seq linkid +2 NULL 12 2 3 11 +SELECT * FROM graph WHERE latch = '2' AND destid = 1 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 2 and weight = 3; +latch origid destid weight seq linkid +2 NULL 2 3 4 4 +SELECT * FROM graph WHERE latch = '2' AND destid = 3 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 4 and weight = 3; +latch origid destid weight seq linkid +2 NULL 4 3 4 2 +SELECT * FROM graph WHERE latch = '2' AND destid = 5 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 6 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 7 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 8 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 9 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 10 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 11 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 12 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = NULL; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = NULL; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2'; +latch origid destid weight seq linkid +# Dijkstras algorithm tests +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1 AND destid=1; +latch origid destid weight seq linkid +dijkstras 1 1 NULL 0 1 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1 AND destid=2; +latch origid destid weight seq linkid +dijkstras 1 2 NULL 0 1 +dijkstras 1 2 1 1 2 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=2 AND destid=1; +latch origid destid weight seq linkid +dijkstras 2 1 NULL 0 2 +dijkstras 2 1 1 1 1 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1 AND destid=4; +latch origid destid weight seq linkid +dijkstras 1 4 NULL 0 1 +dijkstras 1 4 1 1 3 +dijkstras 1 4 1 2 4 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=4 AND destid=1; +latch origid destid weight seq linkid +dijkstras 4 1 NULL 0 4 +dijkstras 4 1 1 1 3 +dijkstras 4 1 1 2 1 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1 AND destid=5; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1 AND destid=666; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='dijkstras' AND origid=5 AND destid=7; +latch origid destid weight seq linkid +dijkstras 5 7 NULL 0 5 +dijkstras 5 7 1 1 7 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=7 AND destid=5; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='dijkstras' AND origid=10 AND destid=11; +latch origid destid weight seq linkid +dijkstras 10 11 NULL 0 10 +dijkstras 10 11 1 1 11 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=10 AND destid=12; +latch origid destid weight seq linkid +dijkstras 10 12 NULL 0 10 +dijkstras 10 12 1 1 11 +dijkstras 10 12 1 2 12 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=11 AND destid=10; +latch origid destid weight seq linkid +dijkstras 11 10 NULL 0 11 +dijkstras 11 10 1 1 12 +dijkstras 11 10 1 2 10 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=11 AND destid=12; +latch origid destid weight seq linkid +dijkstras 11 12 NULL 0 11 +dijkstras 11 12 1 1 12 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=12 AND destid=10; +latch origid destid weight seq linkid +dijkstras 12 10 NULL 0 12 +dijkstras 12 10 1 1 10 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=12 AND destid=11; +latch origid destid weight seq linkid +dijkstras 12 11 NULL 0 12 +dijkstras 12 11 1 1 10 +dijkstras 12 11 1 2 11 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1; +latch origid destid weight seq linkid +dijkstras 1 NULL 2 4 4 +dijkstras 1 NULL 1 3 3 +dijkstras 1 NULL 1 2 2 +dijkstras 1 NULL 0 1 1 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=2; +latch origid destid weight seq linkid +dijkstras 2 NULL 3 4 4 +dijkstras 2 NULL 2 3 3 +dijkstras 2 NULL 1 2 1 +dijkstras 2 NULL 0 1 2 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=3; +latch origid destid weight seq linkid +dijkstras 3 NULL 2 4 2 +dijkstras 3 NULL 1 3 4 +dijkstras 3 NULL 1 2 1 +dijkstras 3 NULL 0 1 3 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=4; +latch origid destid weight seq linkid +dijkstras 4 NULL 3 4 2 +dijkstras 4 NULL 2 3 1 +dijkstras 4 NULL 1 2 3 +dijkstras 4 NULL 0 1 4 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=5; +latch origid destid weight seq linkid +dijkstras 5 NULL 1 3 7 +dijkstras 5 NULL 1 2 6 +dijkstras 5 NULL 0 1 5 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=6; +latch origid destid weight seq linkid +dijkstras 6 NULL 2 3 7 +dijkstras 6 NULL 1 2 5 +dijkstras 6 NULL 0 1 6 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=7; +latch origid destid weight seq linkid +dijkstras 7 NULL 0 1 7 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='dijkstras' AND origid=9; +latch origid destid weight seq linkid +dijkstras 9 NULL 0 1 9 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=10; +latch origid destid weight seq linkid +dijkstras 10 NULL 2 3 12 +dijkstras 10 NULL 1 2 11 +dijkstras 10 NULL 0 1 10 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=11; +latch origid destid weight seq linkid +dijkstras 11 NULL 2 3 10 +dijkstras 11 NULL 1 2 12 +dijkstras 11 NULL 0 1 11 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=12; +latch origid destid weight seq linkid +dijkstras 12 NULL 2 3 11 +dijkstras 12 NULL 1 2 10 +dijkstras 12 NULL 0 1 12 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=666; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='dijkstras' AND destid=1; +latch origid destid weight seq linkid +dijkstras NULL 1 2 4 4 +dijkstras NULL 1 1 3 3 +dijkstras NULL 1 1 2 2 +dijkstras NULL 1 0 1 1 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=2; +latch origid destid weight seq linkid +dijkstras NULL 2 3 4 4 +dijkstras NULL 2 2 3 3 +dijkstras NULL 2 1 2 1 +dijkstras NULL 2 0 1 2 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=3; +latch origid destid weight seq linkid +dijkstras NULL 3 2 4 2 +dijkstras NULL 3 1 3 4 +dijkstras NULL 3 1 2 1 +dijkstras NULL 3 0 1 3 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=4; +latch origid destid weight seq linkid +dijkstras NULL 4 3 4 2 +dijkstras NULL 4 2 3 1 +dijkstras NULL 4 1 2 3 +dijkstras NULL 4 0 1 4 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=5; +latch origid destid weight seq linkid +dijkstras NULL 5 1 3 7 +dijkstras NULL 5 1 2 6 +dijkstras NULL 5 0 1 5 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=6; +latch origid destid weight seq linkid +dijkstras NULL 6 2 3 7 +dijkstras NULL 6 1 2 5 +dijkstras NULL 6 0 1 6 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=7; +latch origid destid weight seq linkid +dijkstras NULL 7 0 1 7 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='dijkstras' AND destid=9; +latch origid destid weight seq linkid +dijkstras NULL 9 0 1 9 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=10; +latch origid destid weight seq linkid +dijkstras NULL 10 2 3 12 +dijkstras NULL 10 1 2 11 +dijkstras NULL 10 0 1 10 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=11; +latch origid destid weight seq linkid +dijkstras NULL 11 2 3 10 +dijkstras NULL 11 1 2 12 +dijkstras NULL 11 0 1 11 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=12; +latch origid destid weight seq linkid +dijkstras NULL 12 2 3 11 +dijkstras NULL 12 1 2 10 +dijkstras NULL 12 0 1 12 +# legacy string number +SELECT * FROM graph WHERE latch='1' AND origid=1 AND destid=1; +latch origid destid weight seq linkid +1 1 1 NULL 0 1 +SELECT * FROM graph WHERE latch='1' AND origid=1 AND destid=2; +latch origid destid weight seq linkid +1 1 2 NULL 0 1 +1 1 2 1 1 2 +SELECT * FROM graph WHERE latch='1' AND origid=2 AND destid=1; +latch origid destid weight seq linkid +1 2 1 NULL 0 2 +1 2 1 1 1 1 +SELECT * FROM graph WHERE latch='1' AND origid=1 AND destid=4; +latch origid destid weight seq linkid +1 1 4 NULL 0 1 +1 1 4 1 1 3 +1 1 4 1 2 4 +SELECT * FROM graph WHERE latch='1' AND origid=4 AND destid=1; +latch origid destid weight seq linkid +1 4 1 NULL 0 4 +1 4 1 1 1 3 +1 4 1 1 2 1 +SELECT * FROM graph WHERE latch='1' AND origid=1 AND destid=5; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='1' AND origid=1 AND destid=666; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='1' AND origid=5 AND destid=7; +latch origid destid weight seq linkid +1 5 7 NULL 0 5 +1 5 7 1 1 7 +SELECT * FROM graph WHERE latch='1' AND origid=7 AND destid=5; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='1' AND origid=10 AND destid=11; +latch origid destid weight seq linkid +1 10 11 NULL 0 10 +1 10 11 1 1 11 +SELECT * FROM graph WHERE latch='1' AND origid=10 AND destid=12; +latch origid destid weight seq linkid +1 10 12 NULL 0 10 +1 10 12 1 1 11 +1 10 12 1 2 12 +SELECT * FROM graph WHERE latch='1' AND origid=11 AND destid=10; +latch origid destid weight seq linkid +1 11 10 NULL 0 11 +1 11 10 1 1 12 +1 11 10 1 2 10 +SELECT * FROM graph WHERE latch='1' AND origid=11 AND destid=12; +latch origid destid weight seq linkid +1 11 12 NULL 0 11 +1 11 12 1 1 12 +SELECT * FROM graph WHERE latch='1' AND origid=12 AND destid=10; +latch origid destid weight seq linkid +1 12 10 NULL 0 12 +1 12 10 1 1 10 +SELECT * FROM graph WHERE latch='1' AND origid=12 AND destid=11; +latch origid destid weight seq linkid +1 12 11 NULL 0 12 +1 12 11 1 1 10 +1 12 11 1 2 11 +SELECT * FROM graph WHERE latch='1' AND origid=1; +latch origid destid weight seq linkid +1 1 NULL 2 4 4 +1 1 NULL 1 3 3 +1 1 NULL 1 2 2 +1 1 NULL 0 1 1 +SELECT * FROM graph WHERE latch='1' AND origid=2; +latch origid destid weight seq linkid +1 2 NULL 3 4 4 +1 2 NULL 2 3 3 +1 2 NULL 1 2 1 +1 2 NULL 0 1 2 +SELECT * FROM graph WHERE latch='1' AND origid=3; +latch origid destid weight seq linkid +1 3 NULL 2 4 2 +1 3 NULL 1 3 4 +1 3 NULL 1 2 1 +1 3 NULL 0 1 3 +SELECT * FROM graph WHERE latch='1' AND origid=4; +latch origid destid weight seq linkid +1 4 NULL 3 4 2 +1 4 NULL 2 3 1 +1 4 NULL 1 2 3 +1 4 NULL 0 1 4 +SELECT * FROM graph WHERE latch='1' AND origid=5; +latch origid destid weight seq linkid +1 5 NULL 1 3 7 +1 5 NULL 1 2 6 +1 5 NULL 0 1 5 +SELECT * FROM graph WHERE latch='1' AND origid=6; +latch origid destid weight seq linkid +1 6 NULL 2 3 7 +1 6 NULL 1 2 5 +1 6 NULL 0 1 6 +SELECT * FROM graph WHERE latch='1' AND origid=7; +latch origid destid weight seq linkid +1 7 NULL 0 1 7 +SELECT * FROM graph WHERE latch='1' AND origid=8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='1' AND origid=9; +latch origid destid weight seq linkid +1 9 NULL 0 1 9 +SELECT * FROM graph WHERE latch='1' AND origid=10; +latch origid destid weight seq linkid +1 10 NULL 2 3 12 +1 10 NULL 1 2 11 +1 10 NULL 0 1 10 +SELECT * FROM graph WHERE latch='1' AND origid=11; +latch origid destid weight seq linkid +1 11 NULL 2 3 10 +1 11 NULL 1 2 12 +1 11 NULL 0 1 11 +SELECT * FROM graph WHERE latch='1' AND origid=12; +latch origid destid weight seq linkid +1 12 NULL 2 3 11 +1 12 NULL 1 2 10 +1 12 NULL 0 1 12 +SELECT * FROM graph WHERE latch='1' AND origid=666; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='1' AND destid=1; +latch origid destid weight seq linkid +1 NULL 1 2 4 4 +1 NULL 1 1 3 3 +1 NULL 1 1 2 2 +1 NULL 1 0 1 1 +SELECT * FROM graph WHERE latch='1' AND destid=2; +latch origid destid weight seq linkid +1 NULL 2 3 4 4 +1 NULL 2 2 3 3 +1 NULL 2 1 2 1 +1 NULL 2 0 1 2 +SELECT * FROM graph WHERE latch='1' AND destid=3; +latch origid destid weight seq linkid +1 NULL 3 2 4 2 +1 NULL 3 1 3 4 +1 NULL 3 1 2 1 +1 NULL 3 0 1 3 +SELECT * FROM graph WHERE latch='1' AND destid=4; +latch origid destid weight seq linkid +1 NULL 4 3 4 2 +1 NULL 4 2 3 1 +1 NULL 4 1 2 3 +1 NULL 4 0 1 4 +SELECT * FROM graph WHERE latch='1' AND destid=5; +latch origid destid weight seq linkid +1 NULL 5 1 3 7 +1 NULL 5 1 2 6 +1 NULL 5 0 1 5 +SELECT * FROM graph WHERE latch='1' AND destid=6; +latch origid destid weight seq linkid +1 NULL 6 2 3 7 +1 NULL 6 1 2 5 +1 NULL 6 0 1 6 +SELECT * FROM graph WHERE latch='1' AND destid=7; +latch origid destid weight seq linkid +1 NULL 7 0 1 7 +SELECT * FROM graph WHERE latch='1' AND destid=8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='1' AND destid=9; +latch origid destid weight seq linkid +1 NULL 9 0 1 9 +SELECT * FROM graph WHERE latch='1' AND destid=10; +latch origid destid weight seq linkid +1 NULL 10 2 3 12 +1 NULL 10 1 2 11 +1 NULL 10 0 1 10 +SELECT * FROM graph WHERE latch='1' AND destid=11; +latch origid destid weight seq linkid +1 NULL 11 2 3 10 +1 NULL 11 1 2 12 +1 NULL 11 0 1 11 +SELECT * FROM graph WHERE latch='1' AND destid=12; +latch origid destid weight seq linkid +1 NULL 12 2 3 11 +1 NULL 12 1 2 10 +1 NULL 12 0 1 12 +INSERT INTO graph_base(from_id, to_id) VALUES (11,13); +INSERT INTO graph_base(from_id, to_id) VALUES (10,14); +INSERT INTO graph_base(from_id, to_id) VALUES (14,13); +SELECT * FROM graph WHERE latch='dijkstras' AND origid=10 AND destid=13; +latch origid destid weight seq linkid +dijkstras 10 13 NULL 0 10 +dijkstras 10 13 1 1 11 +dijkstras 10 13 1 2 13 +DELETE FROM graph_base where from_id=10 and to_id=11; +INSERT INTO graph_base(from_id, to_id) VALUES (10,15); +INSERT INTO graph_base(from_id, to_id) VALUES (15,13); +SELECT * FROM graph WHERE latch='dijkstras' AND origid=10 AND destid=13; +latch origid destid weight seq linkid +dijkstras 10 13 NULL 0 10 +dijkstras 10 13 1 1 14 +dijkstras 10 13 1 2 13 +INSERT INTO graph_base(from_id, to_id) VALUES (10,11); +SELECT * FROM graph WHERE latch='dijkstras' AND origid=10 AND destid=13; +latch origid destid weight seq linkid +dijkstras 10 13 NULL 0 10 +dijkstras 10 13 1 1 11 +dijkstras 10 13 1 2 13 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1; +latch origid destid weight seq linkid +dijkstras 1 NULL 2 4 4 +dijkstras 1 NULL 1 3 3 +dijkstras 1 NULL 1 2 2 +dijkstras 1 NULL 0 1 1 +INSERT INTO graph_base(from_id, to_id) VALUES (21,22); +SELECT * FROM graph WHERE latch='dijkstras' AND origid=21; +latch origid destid weight seq linkid +dijkstras 21 NULL 1 2 22 +dijkstras 21 NULL 0 1 21 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=22; +latch origid destid weight seq linkid +dijkstras 22 NULL 0 1 22 +INSERT INTO graph_base(from_id, to_id) VALUES (4,17); +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1; +latch origid destid weight seq linkid +dijkstras 1 NULL 3 5 17 +dijkstras 1 NULL 2 4 4 +dijkstras 1 NULL 1 3 3 +dijkstras 1 NULL 1 2 2 +dijkstras 1 NULL 0 1 1 +INSERT INTO graph_base(from_id, to_id) VALUES (4,16); +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1; +latch origid destid weight seq linkid +dijkstras 1 NULL 3 6 17 +dijkstras 1 NULL 3 5 16 +dijkstras 1 NULL 2 4 4 +dijkstras 1 NULL 1 3 3 +dijkstras 1 NULL 1 2 2 +dijkstras 1 NULL 0 1 1 +INSERT INTO graph_base(from_id, to_id) VALUES (17,18); +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1; +latch origid destid weight seq linkid +dijkstras 1 NULL 4 7 18 +dijkstras 1 NULL 3 6 17 +dijkstras 1 NULL 3 5 16 +dijkstras 1 NULL 2 4 4 +dijkstras 1 NULL 1 3 3 +dijkstras 1 NULL 1 2 2 +dijkstras 1 NULL 0 1 1 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=1; +latch origid destid weight seq linkid +dijkstras NULL 1 4 7 18 +dijkstras NULL 1 3 6 17 +dijkstras NULL 1 3 5 16 +dijkstras NULL 1 2 4 4 +dijkstras NULL 1 1 3 3 +dijkstras NULL 1 1 2 2 +dijkstras NULL 1 0 1 1 +# Now we add a connection from 4->6 +INSERT INTO graph_base (from_id,to_id) VALUES (4,6); +# And delete all references to node 5 +DELETE FROM graph_base WHERE from_id=5; +DELETE FROM graph_base WHERE from_id=3 AND to_id=5; +# which means there is a path in one direction only 1>3>4>6 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1 AND destid=6; +latch origid destid weight seq linkid +dijkstras 1 6 NULL 0 1 +dijkstras 1 6 1 1 3 +dijkstras 1 6 1 2 4 +dijkstras 1 6 1 3 6 +# but not 6>4>3>1 (so no result) +SELECT * FROM graph WHERE latch='dijkstras' AND origid=6 AND destid=1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='1' AND origid=1 AND destid=6; +latch origid destid weight seq linkid +1 1 6 NULL 0 1 +1 1 6 1 1 3 +1 1 6 1 2 4 +1 1 6 1 3 6 +SELECT * FROM graph WHERE latch='1' AND origid=6 AND destid=1; +latch origid destid weight seq linkid +DELETE FROM graph_base; +FLUSH TABLES; +TRUNCATE TABLE graph_base; +DROP TABLE graph_base; +DROP TABLE graph; diff --git a/storage/oqgraph/mysql-test/oqgraph/general-MyISAM.test b/storage/oqgraph/mysql-test/oqgraph/general-MyISAM.test new file mode 100644 index 00000000000..f1e59e54207 --- /dev/null +++ b/storage/oqgraph/mysql-test/oqgraph/general-MyISAM.test @@ -0,0 +1,3 @@ +# This is a maintainer generated file. Generated at Wednesday 5 February 22:26:12 CST 2014. +--let $oqgraph_use_table_type= MyISAM +--source general.inc diff --git a/storage/oqgraph/mysql-test/oqgraph/general-innodb.result b/storage/oqgraph/mysql-test/oqgraph/general-innodb.result new file mode 100644 index 00000000000..cf9c83144b8 --- /dev/null +++ b/storage/oqgraph/mysql-test/oqgraph/general-innodb.result @@ -0,0 +1,1441 @@ +DROP TABLE IF EXISTS graph_base; +DROP TABLE IF EXISTS graph; +DROP TABLE IF EXISTS graph2; +Performing OQGraph General test suite for ENGINE=innodb +CREATE TABLE graph_base ( +from_id INT UNSIGNED NOT NULL, +to_id INT UNSIGNED NOT NULL, +PRIMARY KEY (from_id,to_id), +INDEX (to_id) +) ENGINE= innodb ; +CREATE TABLE graph ( +latch VARCHAR(32) NULL, +origid BIGINT UNSIGNED NULL, +destid BIGINT UNSIGNED NULL, +weight DOUBLE NULL, +seq BIGINT UNSIGNED NULL, +linkid BIGINT UNSIGNED NULL, +KEY (latch, origid, destid) USING HASH, +KEY (latch, destid, origid) USING HASH +) ENGINE=OQGRAPH DATA_TABLE='graph_base' ORIGID='from_id', DESTID='to_id'; +select * from graph; +latch origid destid weight seq linkid +INSERT INTO graph_base(from_id, to_id) VALUES (1,2), (2,1); +INSERT INTO graph_base(from_id, to_id) VALUES (1,3), (3,1); +INSERT INTO graph_base(from_id, to_id) VALUES (3,4), (4,3); +INSERT INTO graph_base(from_id, to_id) VALUES (5,6), (6,5); +INSERT INTO graph_base(from_id, to_id) VALUES (5,7); +INSERT INTO graph_base(from_id, to_id) VALUES (9,9); +INSERT INTO graph_base(from_id, to_id) VALUES (10,11); +INSERT INTO graph_base(from_id, to_id) VALUES (11,12); +INSERT INTO graph_base(from_id, to_id) VALUES (12,10); +# Return all edges +SELECT * FROM graph; +latch origid destid weight seq linkid +NULL 1 2 1 NULL NULL +NULL 1 3 1 NULL NULL +NULL 2 1 1 NULL NULL +NULL 3 1 1 NULL NULL +NULL 3 4 1 NULL NULL +NULL 4 3 1 NULL NULL +NULL 5 6 1 NULL NULL +NULL 5 7 1 NULL NULL +NULL 6 5 1 NULL NULL +NULL 9 9 1 NULL NULL +NULL 10 11 1 NULL NULL +NULL 11 12 1 NULL NULL +NULL 12 10 1 NULL NULL +# Currently count should be 13 +SELECT count(*) FROM graph; +count(*) +13 +# Return all edges when latch is NULL - this is different to latch='' and same as no where clause +SELECT * FROM graph where latch is NULL; +latch origid destid weight seq linkid +NULL 1 2 1 NULL NULL +NULL 1 3 1 NULL NULL +NULL 2 1 1 NULL NULL +NULL 3 1 1 NULL NULL +NULL 3 4 1 NULL NULL +NULL 4 3 1 NULL NULL +NULL 5 6 1 NULL NULL +NULL 5 7 1 NULL NULL +NULL 6 5 1 NULL NULL +NULL 9 9 1 NULL NULL +NULL 10 11 1 NULL NULL +NULL 11 12 1 NULL NULL +NULL 12 10 1 NULL NULL +# Return all vertices, and subsets of vertices +SELECT * FROM graph where latch=''; +latch origid destid weight seq linkid + NULL NULL NULL NULL 1 + NULL NULL NULL NULL 2 + NULL NULL NULL NULL 3 + NULL NULL NULL NULL 4 + NULL NULL NULL NULL 5 + NULL NULL NULL NULL 6 + NULL NULL NULL NULL 7 + NULL NULL NULL NULL 9 + NULL NULL NULL NULL 10 + NULL NULL NULL NULL 11 + NULL NULL NULL NULL 12 +SELECT * FROM graph where latch='0'; +latch origid destid weight seq linkid +0 NULL NULL NULL NULL 1 +0 NULL NULL NULL NULL 2 +0 NULL NULL NULL NULL 3 +0 NULL NULL NULL NULL 4 +0 NULL NULL NULL NULL 5 +0 NULL NULL NULL NULL 6 +0 NULL NULL NULL NULL 7 +0 NULL NULL NULL NULL 9 +0 NULL NULL NULL NULL 10 +0 NULL NULL NULL NULL 11 +0 NULL NULL NULL NULL 12 +# Currently count should be 11 +SELECT count(*) FROM graph where latch=''; +count(*) +11 +SELECT * FROM graph where latch='' and linkid = 2; +latch origid destid weight seq linkid + NULL NULL NULL NULL 2 +SELECT * FROM graph where latch='' and (linkid > 2 and linkid < 6); +latch origid destid weight seq linkid + NULL NULL NULL NULL 3 + NULL NULL NULL NULL 4 + NULL NULL NULL NULL 5 +SELECT * FROM graph where latch='' and linkid = NULL; +latch origid destid weight seq linkid +SELECT * FROM graph where latch='' and linkid = 666; +latch origid destid weight seq linkid +SELECT origid as `from`, linkid as `to` FROM graph where latch='' and origid = 1; +from to +1 3 +1 2 +SELECT origid as `from`, linkid as `to` FROM graph where latch='' and origid = 2; +from to +2 1 +SELECT origid as `from`, linkid as `to` FROM graph where latch='' and origid = 4; +from to +4 3 +SELECT origid as `from`, linkid as `to` FROM graph where latch='' and origid = 9; +from to +9 9 +SELECT origid as `from`, linkid as `to` FROM graph where latch='' and origid = 10; +from to +10 11 +SELECT origid as `from`, linkid as `to` FROM graph where latch='' and origid = NULL; +from to +SELECT origid as `from`, linkid as `to` FROM graph where latch='' and origid = 666; +from to +SELECT linkid as `from`, destid as `to` FROM graph where latch='' and destid = 1; +from to +3 1 +2 1 +SELECT linkid as `from`, destid as `to` FROM graph where latch='' and destid = 2; +from to +1 2 +SELECT linkid as `from`, destid as `to` FROM graph where latch='' and destid = 4; +from to +3 4 +SELECT linkid as `from`, destid as `to` FROM graph where latch='' and destid = 9; +from to +9 9 +SELECT linkid as `from`, destid as `to` FROM graph where latch='' and destid = 10; +from to +12 10 +SELECT linkid as `from`, destid as `to` FROM graph where latch='' and destid = NULL; +from to +SELECT linkid as `from`, destid as `to` FROM graph where latch='' and destid = 666; +from to +SELECT * FROM graph where latch='0'; +latch origid destid weight seq linkid +0 NULL NULL NULL NULL 1 +0 NULL NULL NULL NULL 2 +0 NULL NULL NULL NULL 3 +0 NULL NULL NULL NULL 4 +0 NULL NULL NULL NULL 5 +0 NULL NULL NULL NULL 6 +0 NULL NULL NULL NULL 7 +0 NULL NULL NULL NULL 9 +0 NULL NULL NULL NULL 10 +0 NULL NULL NULL NULL 11 +0 NULL NULL NULL NULL 12 +SELECT count(*) FROM graph where latch='0'; +count(*) +11 +SELECT * FROM graph where latch='0' and linkid = 2; +latch origid destid weight seq linkid +0 NULL NULL NULL NULL 2 +SELECT * FROM graph where latch='0' and (linkid > 2 and linkid < 6); +latch origid destid weight seq linkid +0 NULL NULL NULL NULL 3 +0 NULL NULL NULL NULL 4 +0 NULL NULL NULL NULL 5 +SELECT origid as `from`, linkid as `to` FROM graph where latch='0' and origid = 1; +from to +1 3 +1 2 +SELECT origid as `from`, linkid as `to` FROM graph where latch='0' and origid = 2; +from to +2 1 +SELECT origid as `from`, linkid as `to` FROM graph where latch='0' and origid = 4; +from to +4 3 +SELECT origid as `from`, linkid as `to` FROM graph where latch='0' and origid = 9; +from to +9 9 +SELECT origid as `from`, linkid as `to` FROM graph where latch='0' and origid = 10; +from to +10 11 +SELECT linkid as `from`, destid as `to` FROM graph where latch='0' and destid = 1; +from to +3 1 +2 1 +SELECT linkid as `from`, destid as `to` FROM graph where latch='0' and destid = 2; +from to +1 2 +SELECT linkid as `from`, destid as `to` FROM graph where latch='0' and destid = 4; +from to +3 4 +SELECT linkid as `from`, destid as `to` FROM graph where latch='0' and destid = 9; +from to +9 9 +SELECT linkid as `from`, destid as `to` FROM graph where latch='0' and destid = 10; +from to +12 10 +# Breadth-first search tests +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 1; +latch origid destid weight seq linkid +breadth_first 1 NULL 2 4 4 +breadth_first 1 NULL 1 3 3 +breadth_first 1 NULL 1 2 2 +breadth_first 1 NULL 0 1 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 2; +latch origid destid weight seq linkid +breadth_first 2 NULL 3 4 4 +breadth_first 2 NULL 2 3 3 +breadth_first 2 NULL 1 2 1 +breadth_first 2 NULL 0 1 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 3; +latch origid destid weight seq linkid +breadth_first 3 NULL 2 4 2 +breadth_first 3 NULL 1 3 4 +breadth_first 3 NULL 1 2 1 +breadth_first 3 NULL 0 1 3 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 4; +latch origid destid weight seq linkid +breadth_first 4 NULL 3 4 2 +breadth_first 4 NULL 2 3 1 +breadth_first 4 NULL 1 2 3 +breadth_first 4 NULL 0 1 4 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 5; +latch origid destid weight seq linkid +breadth_first 5 NULL 1 3 7 +breadth_first 5 NULL 1 2 6 +breadth_first 5 NULL 0 1 5 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 6; +latch origid destid weight seq linkid +breadth_first 6 NULL 2 3 7 +breadth_first 6 NULL 1 2 5 +breadth_first 6 NULL 0 1 6 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 7; +latch origid destid weight seq linkid +breadth_first 7 NULL 0 1 7 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 9; +latch origid destid weight seq linkid +breadth_first 9 NULL 0 1 9 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 10; +latch origid destid weight seq linkid +breadth_first 10 NULL 2 3 12 +breadth_first 10 NULL 1 2 11 +breadth_first 10 NULL 0 1 10 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 11; +latch origid destid weight seq linkid +breadth_first 11 NULL 2 3 10 +breadth_first 11 NULL 1 2 12 +breadth_first 11 NULL 0 1 11 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 12; +latch origid destid weight seq linkid +breadth_first 12 NULL 2 3 11 +breadth_first 12 NULL 1 2 10 +breadth_first 12 NULL 0 1 12 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 666; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 1 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 1 NULL 1 3 3 +breadth_first 1 NULL 1 2 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 2 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 2 NULL 1 2 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 3 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 3 NULL 1 3 4 +breadth_first 3 NULL 1 2 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 4 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 4 NULL 1 2 3 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 5 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 5 NULL 1 3 7 +breadth_first 5 NULL 1 2 6 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 6 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 6 NULL 1 2 5 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 7 AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 8 AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 9 AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 10 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 10 NULL 1 2 11 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 11 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 11 NULL 1 2 12 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 12 AND weight = 1; +latch origid destid weight seq linkid +breadth_first 12 NULL 1 2 10 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 1 AND weight = 1; +count(*) +2 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 2 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 3 AND weight = 1; +count(*) +2 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 4 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 5 AND weight = 1; +count(*) +2 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 6 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 7 AND weight = 1; +count(*) +0 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 8 AND weight = 1; +count(*) +0 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 9 AND weight = 1; +count(*) +0 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 10 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 11 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = 'breadth_first' AND origid = 12 AND weight = 1; +count(*) +1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 1 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 1 NULL 2 4 4 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 2 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 2 NULL 2 3 3 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 3 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 3 NULL 2 4 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 4 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 4 NULL 2 3 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 5 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 6 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 6 NULL 2 3 7 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 7 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 8 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 9 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 10 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 10 NULL 2 3 12 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 11 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 11 NULL 2 3 10 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 12 AND weight = 2; +latch origid destid weight seq linkid +breadth_first 12 NULL 2 3 11 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 1 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 2 AND weight = 3; +latch origid destid weight seq linkid +breadth_first 2 NULL 3 4 4 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 3 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 4 AND weight = 3; +latch origid destid weight seq linkid +breadth_first 4 NULL 3 4 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 5 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 6 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 7 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 8 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 9 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 10 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 11 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 12 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 1 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 1 NULL 2 4 4 +breadth_first 1 NULL 1 3 3 +breadth_first 1 NULL 1 2 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 2 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 2 NULL 2 3 3 +breadth_first 2 NULL 1 2 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 3 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 3 NULL 2 4 2 +breadth_first 3 NULL 1 3 4 +breadth_first 3 NULL 1 2 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 4 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 4 NULL 2 3 1 +breadth_first 4 NULL 1 2 3 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 5 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 5 NULL 1 3 7 +breadth_first 5 NULL 1 2 6 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 6 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 6 NULL 2 3 7 +breadth_first 6 NULL 1 2 5 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 7 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 8 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 9 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 10 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 10 NULL 2 3 12 +breadth_first 10 NULL 1 2 11 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 11 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 11 NULL 2 3 10 +breadth_first 11 NULL 1 2 12 +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = 12 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +breadth_first 12 NULL 2 3 11 +breadth_first 12 NULL 1 2 10 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 1; +latch origid destid weight seq linkid +breadth_first NULL 1 2 4 4 +breadth_first NULL 1 1 3 3 +breadth_first NULL 1 1 2 2 +breadth_first NULL 1 0 1 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 2; +latch origid destid weight seq linkid +breadth_first NULL 2 3 4 4 +breadth_first NULL 2 2 3 3 +breadth_first NULL 2 1 2 1 +breadth_first NULL 2 0 1 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 3; +latch origid destid weight seq linkid +breadth_first NULL 3 2 4 2 +breadth_first NULL 3 1 3 4 +breadth_first NULL 3 1 2 1 +breadth_first NULL 3 0 1 3 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 4; +latch origid destid weight seq linkid +breadth_first NULL 4 3 4 2 +breadth_first NULL 4 2 3 1 +breadth_first NULL 4 1 2 3 +breadth_first NULL 4 0 1 4 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 5; +latch origid destid weight seq linkid +breadth_first NULL 5 1 3 7 +breadth_first NULL 5 1 2 6 +breadth_first NULL 5 0 1 5 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 6; +latch origid destid weight seq linkid +breadth_first NULL 6 2 3 7 +breadth_first NULL 6 1 2 5 +breadth_first NULL 6 0 1 6 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 7; +latch origid destid weight seq linkid +breadth_first NULL 7 0 1 7 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 9; +latch origid destid weight seq linkid +breadth_first NULL 9 0 1 9 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 10; +latch origid destid weight seq linkid +breadth_first NULL 10 2 3 12 +breadth_first NULL 10 1 2 11 +breadth_first NULL 10 0 1 10 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 11; +latch origid destid weight seq linkid +breadth_first NULL 11 2 3 10 +breadth_first NULL 11 1 2 12 +breadth_first NULL 11 0 1 11 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 12; +latch origid destid weight seq linkid +breadth_first NULL 12 2 3 11 +breadth_first NULL 12 1 2 10 +breadth_first NULL 12 0 1 12 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 1 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 1 1 3 3 +breadth_first NULL 1 1 2 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 2 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 2 1 2 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 3 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 3 1 3 4 +breadth_first NULL 3 1 2 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 4 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 4 1 2 3 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 5 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 5 1 3 7 +breadth_first NULL 5 1 2 6 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 6 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 6 1 2 5 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 7 and weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 8 and weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 9 and weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 10 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 10 1 2 11 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 11 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 11 1 2 12 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 12 and weight = 1; +latch origid destid weight seq linkid +breadth_first NULL 12 1 2 10 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 1 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 1 2 4 4 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 2 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 2 2 3 3 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 3 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 3 2 4 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 4 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 4 2 3 1 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 5 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 6 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 6 2 3 7 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 7 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 8 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 9 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 10 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 10 2 3 12 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 11 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 11 2 3 10 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 12 and weight = 2; +latch origid destid weight seq linkid +breadth_first NULL 12 2 3 11 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 1 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 2 and weight = 3; +latch origid destid weight seq linkid +breadth_first NULL 2 3 4 4 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 3 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 4 and weight = 3; +latch origid destid weight seq linkid +breadth_first NULL 4 3 4 2 +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 5 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 6 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 7 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 8 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 9 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 10 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 11 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = 12 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND origid = NULL; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND destid = NULL; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first' AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = 'breadth_first'; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 1; +latch origid destid weight seq linkid +2 1 NULL 2 4 4 +2 1 NULL 1 3 3 +2 1 NULL 1 2 2 +2 1 NULL 0 1 1 +SELECT * FROM graph WHERE latch = '2' AND origid = 2; +latch origid destid weight seq linkid +2 2 NULL 3 4 4 +2 2 NULL 2 3 3 +2 2 NULL 1 2 1 +2 2 NULL 0 1 2 +SELECT * FROM graph WHERE latch = '2' AND origid = 3; +latch origid destid weight seq linkid +2 3 NULL 2 4 2 +2 3 NULL 1 3 4 +2 3 NULL 1 2 1 +2 3 NULL 0 1 3 +SELECT * FROM graph WHERE latch = '2' AND origid = 4; +latch origid destid weight seq linkid +2 4 NULL 3 4 2 +2 4 NULL 2 3 1 +2 4 NULL 1 2 3 +2 4 NULL 0 1 4 +SELECT * FROM graph WHERE latch = '2' AND origid = 5; +latch origid destid weight seq linkid +2 5 NULL 1 3 7 +2 5 NULL 1 2 6 +2 5 NULL 0 1 5 +SELECT * FROM graph WHERE latch = '2' AND origid = 6; +latch origid destid weight seq linkid +2 6 NULL 2 3 7 +2 6 NULL 1 2 5 +2 6 NULL 0 1 6 +SELECT * FROM graph WHERE latch = '2' AND origid = 7; +latch origid destid weight seq linkid +2 7 NULL 0 1 7 +SELECT * FROM graph WHERE latch = '2' AND origid = 8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 9; +latch origid destid weight seq linkid +2 9 NULL 0 1 9 +SELECT * FROM graph WHERE latch = '2' AND origid = 10; +latch origid destid weight seq linkid +2 10 NULL 2 3 12 +2 10 NULL 1 2 11 +2 10 NULL 0 1 10 +SELECT * FROM graph WHERE latch = '2' AND origid = 11; +latch origid destid weight seq linkid +2 11 NULL 2 3 10 +2 11 NULL 1 2 12 +2 11 NULL 0 1 11 +SELECT * FROM graph WHERE latch = '2' AND origid = 12; +latch origid destid weight seq linkid +2 12 NULL 2 3 11 +2 12 NULL 1 2 10 +2 12 NULL 0 1 12 +SELECT * FROM graph WHERE latch = '2' AND origid = 666; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 1 AND weight = 1; +latch origid destid weight seq linkid +2 1 NULL 1 3 3 +2 1 NULL 1 2 2 +SELECT * FROM graph WHERE latch = '2' AND origid = 2 AND weight = 1; +latch origid destid weight seq linkid +2 2 NULL 1 2 1 +SELECT * FROM graph WHERE latch = '2' AND origid = 3 AND weight = 1; +latch origid destid weight seq linkid +2 3 NULL 1 3 4 +2 3 NULL 1 2 1 +SELECT * FROM graph WHERE latch = '2' AND origid = 4 AND weight = 1; +latch origid destid weight seq linkid +2 4 NULL 1 2 3 +SELECT * FROM graph WHERE latch = '2' AND origid = 5 AND weight = 1; +latch origid destid weight seq linkid +2 5 NULL 1 3 7 +2 5 NULL 1 2 6 +SELECT * FROM graph WHERE latch = '2' AND origid = 6 AND weight = 1; +latch origid destid weight seq linkid +2 6 NULL 1 2 5 +SELECT * FROM graph WHERE latch = '2' AND origid = 7 AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 8 AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 9 AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 10 AND weight = 1; +latch origid destid weight seq linkid +2 10 NULL 1 2 11 +SELECT * FROM graph WHERE latch = '2' AND origid = 11 AND weight = 1; +latch origid destid weight seq linkid +2 11 NULL 1 2 12 +SELECT * FROM graph WHERE latch = '2' AND origid = 12 AND weight = 1; +latch origid destid weight seq linkid +2 12 NULL 1 2 10 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 1 AND weight = 1; +count(*) +2 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 2 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 3 AND weight = 1; +count(*) +2 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 4 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 5 AND weight = 1; +count(*) +2 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 6 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 7 AND weight = 1; +count(*) +0 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 8 AND weight = 1; +count(*) +0 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 9 AND weight = 1; +count(*) +0 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 10 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 11 AND weight = 1; +count(*) +1 +SELECT count(*) FROM graph WHERE latch = '2' AND origid = 12 AND weight = 1; +count(*) +1 +SELECT * FROM graph WHERE latch = '2' AND origid = 1 AND weight = 2; +latch origid destid weight seq linkid +2 1 NULL 2 4 4 +SELECT * FROM graph WHERE latch = '2' AND origid = 2 AND weight = 2; +latch origid destid weight seq linkid +2 2 NULL 2 3 3 +SELECT * FROM graph WHERE latch = '2' AND origid = 3 AND weight = 2; +latch origid destid weight seq linkid +2 3 NULL 2 4 2 +SELECT * FROM graph WHERE latch = '2' AND origid = 4 AND weight = 2; +latch origid destid weight seq linkid +2 4 NULL 2 3 1 +SELECT * FROM graph WHERE latch = '2' AND origid = 5 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 6 AND weight = 2; +latch origid destid weight seq linkid +2 6 NULL 2 3 7 +SELECT * FROM graph WHERE latch = '2' AND origid = 7 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 8 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 9 AND weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 10 AND weight = 2; +latch origid destid weight seq linkid +2 10 NULL 2 3 12 +SELECT * FROM graph WHERE latch = '2' AND origid = 11 AND weight = 2; +latch origid destid weight seq linkid +2 11 NULL 2 3 10 +SELECT * FROM graph WHERE latch = '2' AND origid = 12 AND weight = 2; +latch origid destid weight seq linkid +2 12 NULL 2 3 11 +SELECT * FROM graph WHERE latch = '2' AND origid = 1 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 2 AND weight = 3; +latch origid destid weight seq linkid +2 2 NULL 3 4 4 +SELECT * FROM graph WHERE latch = '2' AND origid = 3 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 4 AND weight = 3; +latch origid destid weight seq linkid +2 4 NULL 3 4 2 +SELECT * FROM graph WHERE latch = '2' AND origid = 5 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 6 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 7 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 8 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 9 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 10 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 11 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 12 AND weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 1 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 1 NULL 2 4 4 +2 1 NULL 1 3 3 +2 1 NULL 1 2 2 +SELECT * FROM graph WHERE latch = '2' AND origid = 2 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 2 NULL 2 3 3 +2 2 NULL 1 2 1 +SELECT * FROM graph WHERE latch = '2' AND origid = 3 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 3 NULL 2 4 2 +2 3 NULL 1 3 4 +2 3 NULL 1 2 1 +SELECT * FROM graph WHERE latch = '2' AND origid = 4 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 4 NULL 2 3 1 +2 4 NULL 1 2 3 +SELECT * FROM graph WHERE latch = '2' AND origid = 5 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 5 NULL 1 3 7 +2 5 NULL 1 2 6 +SELECT * FROM graph WHERE latch = '2' AND origid = 6 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 6 NULL 2 3 7 +2 6 NULL 1 2 5 +SELECT * FROM graph WHERE latch = '2' AND origid = 7 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 8 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 9 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = 10 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 10 NULL 2 3 12 +2 10 NULL 1 2 11 +SELECT * FROM graph WHERE latch = '2' AND origid = 11 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 11 NULL 2 3 10 +2 11 NULL 1 2 12 +SELECT * FROM graph WHERE latch = '2' AND origid = 12 AND (weight = 1 or weight = 2); +latch origid destid weight seq linkid +2 12 NULL 2 3 11 +2 12 NULL 1 2 10 +SELECT * FROM graph WHERE latch = '2' AND destid = 1; +latch origid destid weight seq linkid +2 NULL 1 2 4 4 +2 NULL 1 1 3 3 +2 NULL 1 1 2 2 +2 NULL 1 0 1 1 +SELECT * FROM graph WHERE latch = '2' AND destid = 2; +latch origid destid weight seq linkid +2 NULL 2 3 4 4 +2 NULL 2 2 3 3 +2 NULL 2 1 2 1 +2 NULL 2 0 1 2 +SELECT * FROM graph WHERE latch = '2' AND destid = 3; +latch origid destid weight seq linkid +2 NULL 3 2 4 2 +2 NULL 3 1 3 4 +2 NULL 3 1 2 1 +2 NULL 3 0 1 3 +SELECT * FROM graph WHERE latch = '2' AND destid = 4; +latch origid destid weight seq linkid +2 NULL 4 3 4 2 +2 NULL 4 2 3 1 +2 NULL 4 1 2 3 +2 NULL 4 0 1 4 +SELECT * FROM graph WHERE latch = '2' AND destid = 5; +latch origid destid weight seq linkid +2 NULL 5 1 3 7 +2 NULL 5 1 2 6 +2 NULL 5 0 1 5 +SELECT * FROM graph WHERE latch = '2' AND destid = 6; +latch origid destid weight seq linkid +2 NULL 6 2 3 7 +2 NULL 6 1 2 5 +2 NULL 6 0 1 6 +SELECT * FROM graph WHERE latch = '2' AND destid = 7; +latch origid destid weight seq linkid +2 NULL 7 0 1 7 +SELECT * FROM graph WHERE latch = '2' AND destid = 8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 9; +latch origid destid weight seq linkid +2 NULL 9 0 1 9 +SELECT * FROM graph WHERE latch = '2' AND destid = 10; +latch origid destid weight seq linkid +2 NULL 10 2 3 12 +2 NULL 10 1 2 11 +2 NULL 10 0 1 10 +SELECT * FROM graph WHERE latch = '2' AND destid = 11; +latch origid destid weight seq linkid +2 NULL 11 2 3 10 +2 NULL 11 1 2 12 +2 NULL 11 0 1 11 +SELECT * FROM graph WHERE latch = '2' AND destid = 12; +latch origid destid weight seq linkid +2 NULL 12 2 3 11 +2 NULL 12 1 2 10 +2 NULL 12 0 1 12 +SELECT * FROM graph WHERE latch = '2' AND destid = 1 and weight = 1; +latch origid destid weight seq linkid +2 NULL 1 1 3 3 +2 NULL 1 1 2 2 +SELECT * FROM graph WHERE latch = '2' AND destid = 2 and weight = 1; +latch origid destid weight seq linkid +2 NULL 2 1 2 1 +SELECT * FROM graph WHERE latch = '2' AND destid = 3 and weight = 1; +latch origid destid weight seq linkid +2 NULL 3 1 3 4 +2 NULL 3 1 2 1 +SELECT * FROM graph WHERE latch = '2' AND destid = 4 and weight = 1; +latch origid destid weight seq linkid +2 NULL 4 1 2 3 +SELECT * FROM graph WHERE latch = '2' AND destid = 5 and weight = 1; +latch origid destid weight seq linkid +2 NULL 5 1 3 7 +2 NULL 5 1 2 6 +SELECT * FROM graph WHERE latch = '2' AND destid = 6 and weight = 1; +latch origid destid weight seq linkid +2 NULL 6 1 2 5 +SELECT * FROM graph WHERE latch = '2' AND destid = 7 and weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 8 and weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 9 and weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 10 and weight = 1; +latch origid destid weight seq linkid +2 NULL 10 1 2 11 +SELECT * FROM graph WHERE latch = '2' AND destid = 11 and weight = 1; +latch origid destid weight seq linkid +2 NULL 11 1 2 12 +SELECT * FROM graph WHERE latch = '2' AND destid = 12 and weight = 1; +latch origid destid weight seq linkid +2 NULL 12 1 2 10 +SELECT * FROM graph WHERE latch = '2' AND destid = 1 and weight = 2; +latch origid destid weight seq linkid +2 NULL 1 2 4 4 +SELECT * FROM graph WHERE latch = '2' AND destid = 2 and weight = 2; +latch origid destid weight seq linkid +2 NULL 2 2 3 3 +SELECT * FROM graph WHERE latch = '2' AND destid = 3 and weight = 2; +latch origid destid weight seq linkid +2 NULL 3 2 4 2 +SELECT * FROM graph WHERE latch = '2' AND destid = 4 and weight = 2; +latch origid destid weight seq linkid +2 NULL 4 2 3 1 +SELECT * FROM graph WHERE latch = '2' AND destid = 5 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 6 and weight = 2; +latch origid destid weight seq linkid +2 NULL 6 2 3 7 +SELECT * FROM graph WHERE latch = '2' AND destid = 7 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 8 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 9 and weight = 2; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 10 and weight = 2; +latch origid destid weight seq linkid +2 NULL 10 2 3 12 +SELECT * FROM graph WHERE latch = '2' AND destid = 11 and weight = 2; +latch origid destid weight seq linkid +2 NULL 11 2 3 10 +SELECT * FROM graph WHERE latch = '2' AND destid = 12 and weight = 2; +latch origid destid weight seq linkid +2 NULL 12 2 3 11 +SELECT * FROM graph WHERE latch = '2' AND destid = 1 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 2 and weight = 3; +latch origid destid weight seq linkid +2 NULL 2 3 4 4 +SELECT * FROM graph WHERE latch = '2' AND destid = 3 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 4 and weight = 3; +latch origid destid weight seq linkid +2 NULL 4 3 4 2 +SELECT * FROM graph WHERE latch = '2' AND destid = 5 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 6 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 7 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 8 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 9 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 10 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 11 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = 12 and weight = 3; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND origid = NULL; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND destid = NULL; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2' AND weight = 1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch = '2'; +latch origid destid weight seq linkid +# Dijkstras algorithm tests +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1 AND destid=1; +latch origid destid weight seq linkid +dijkstras 1 1 NULL 0 1 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1 AND destid=2; +latch origid destid weight seq linkid +dijkstras 1 2 NULL 0 1 +dijkstras 1 2 1 1 2 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=2 AND destid=1; +latch origid destid weight seq linkid +dijkstras 2 1 NULL 0 2 +dijkstras 2 1 1 1 1 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1 AND destid=4; +latch origid destid weight seq linkid +dijkstras 1 4 NULL 0 1 +dijkstras 1 4 1 1 3 +dijkstras 1 4 1 2 4 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=4 AND destid=1; +latch origid destid weight seq linkid +dijkstras 4 1 NULL 0 4 +dijkstras 4 1 1 1 3 +dijkstras 4 1 1 2 1 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1 AND destid=5; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1 AND destid=666; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='dijkstras' AND origid=5 AND destid=7; +latch origid destid weight seq linkid +dijkstras 5 7 NULL 0 5 +dijkstras 5 7 1 1 7 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=7 AND destid=5; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='dijkstras' AND origid=10 AND destid=11; +latch origid destid weight seq linkid +dijkstras 10 11 NULL 0 10 +dijkstras 10 11 1 1 11 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=10 AND destid=12; +latch origid destid weight seq linkid +dijkstras 10 12 NULL 0 10 +dijkstras 10 12 1 1 11 +dijkstras 10 12 1 2 12 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=11 AND destid=10; +latch origid destid weight seq linkid +dijkstras 11 10 NULL 0 11 +dijkstras 11 10 1 1 12 +dijkstras 11 10 1 2 10 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=11 AND destid=12; +latch origid destid weight seq linkid +dijkstras 11 12 NULL 0 11 +dijkstras 11 12 1 1 12 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=12 AND destid=10; +latch origid destid weight seq linkid +dijkstras 12 10 NULL 0 12 +dijkstras 12 10 1 1 10 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=12 AND destid=11; +latch origid destid weight seq linkid +dijkstras 12 11 NULL 0 12 +dijkstras 12 11 1 1 10 +dijkstras 12 11 1 2 11 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1; +latch origid destid weight seq linkid +dijkstras 1 NULL 2 4 4 +dijkstras 1 NULL 1 3 3 +dijkstras 1 NULL 1 2 2 +dijkstras 1 NULL 0 1 1 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=2; +latch origid destid weight seq linkid +dijkstras 2 NULL 3 4 4 +dijkstras 2 NULL 2 3 3 +dijkstras 2 NULL 1 2 1 +dijkstras 2 NULL 0 1 2 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=3; +latch origid destid weight seq linkid +dijkstras 3 NULL 2 4 2 +dijkstras 3 NULL 1 3 4 +dijkstras 3 NULL 1 2 1 +dijkstras 3 NULL 0 1 3 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=4; +latch origid destid weight seq linkid +dijkstras 4 NULL 3 4 2 +dijkstras 4 NULL 2 3 1 +dijkstras 4 NULL 1 2 3 +dijkstras 4 NULL 0 1 4 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=5; +latch origid destid weight seq linkid +dijkstras 5 NULL 1 3 7 +dijkstras 5 NULL 1 2 6 +dijkstras 5 NULL 0 1 5 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=6; +latch origid destid weight seq linkid +dijkstras 6 NULL 2 3 7 +dijkstras 6 NULL 1 2 5 +dijkstras 6 NULL 0 1 6 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=7; +latch origid destid weight seq linkid +dijkstras 7 NULL 0 1 7 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='dijkstras' AND origid=9; +latch origid destid weight seq linkid +dijkstras 9 NULL 0 1 9 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=10; +latch origid destid weight seq linkid +dijkstras 10 NULL 2 3 12 +dijkstras 10 NULL 1 2 11 +dijkstras 10 NULL 0 1 10 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=11; +latch origid destid weight seq linkid +dijkstras 11 NULL 2 3 10 +dijkstras 11 NULL 1 2 12 +dijkstras 11 NULL 0 1 11 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=12; +latch origid destid weight seq linkid +dijkstras 12 NULL 2 3 11 +dijkstras 12 NULL 1 2 10 +dijkstras 12 NULL 0 1 12 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=666; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='dijkstras' AND destid=1; +latch origid destid weight seq linkid +dijkstras NULL 1 2 4 4 +dijkstras NULL 1 1 3 3 +dijkstras NULL 1 1 2 2 +dijkstras NULL 1 0 1 1 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=2; +latch origid destid weight seq linkid +dijkstras NULL 2 3 4 4 +dijkstras NULL 2 2 3 3 +dijkstras NULL 2 1 2 1 +dijkstras NULL 2 0 1 2 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=3; +latch origid destid weight seq linkid +dijkstras NULL 3 2 4 2 +dijkstras NULL 3 1 3 4 +dijkstras NULL 3 1 2 1 +dijkstras NULL 3 0 1 3 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=4; +latch origid destid weight seq linkid +dijkstras NULL 4 3 4 2 +dijkstras NULL 4 2 3 1 +dijkstras NULL 4 1 2 3 +dijkstras NULL 4 0 1 4 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=5; +latch origid destid weight seq linkid +dijkstras NULL 5 1 3 7 +dijkstras NULL 5 1 2 6 +dijkstras NULL 5 0 1 5 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=6; +latch origid destid weight seq linkid +dijkstras NULL 6 2 3 7 +dijkstras NULL 6 1 2 5 +dijkstras NULL 6 0 1 6 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=7; +latch origid destid weight seq linkid +dijkstras NULL 7 0 1 7 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='dijkstras' AND destid=9; +latch origid destid weight seq linkid +dijkstras NULL 9 0 1 9 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=10; +latch origid destid weight seq linkid +dijkstras NULL 10 2 3 12 +dijkstras NULL 10 1 2 11 +dijkstras NULL 10 0 1 10 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=11; +latch origid destid weight seq linkid +dijkstras NULL 11 2 3 10 +dijkstras NULL 11 1 2 12 +dijkstras NULL 11 0 1 11 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=12; +latch origid destid weight seq linkid +dijkstras NULL 12 2 3 11 +dijkstras NULL 12 1 2 10 +dijkstras NULL 12 0 1 12 +# legacy string number +SELECT * FROM graph WHERE latch='1' AND origid=1 AND destid=1; +latch origid destid weight seq linkid +1 1 1 NULL 0 1 +SELECT * FROM graph WHERE latch='1' AND origid=1 AND destid=2; +latch origid destid weight seq linkid +1 1 2 NULL 0 1 +1 1 2 1 1 2 +SELECT * FROM graph WHERE latch='1' AND origid=2 AND destid=1; +latch origid destid weight seq linkid +1 2 1 NULL 0 2 +1 2 1 1 1 1 +SELECT * FROM graph WHERE latch='1' AND origid=1 AND destid=4; +latch origid destid weight seq linkid +1 1 4 NULL 0 1 +1 1 4 1 1 3 +1 1 4 1 2 4 +SELECT * FROM graph WHERE latch='1' AND origid=4 AND destid=1; +latch origid destid weight seq linkid +1 4 1 NULL 0 4 +1 4 1 1 1 3 +1 4 1 1 2 1 +SELECT * FROM graph WHERE latch='1' AND origid=1 AND destid=5; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='1' AND origid=1 AND destid=666; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='1' AND origid=5 AND destid=7; +latch origid destid weight seq linkid +1 5 7 NULL 0 5 +1 5 7 1 1 7 +SELECT * FROM graph WHERE latch='1' AND origid=7 AND destid=5; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='1' AND origid=10 AND destid=11; +latch origid destid weight seq linkid +1 10 11 NULL 0 10 +1 10 11 1 1 11 +SELECT * FROM graph WHERE latch='1' AND origid=10 AND destid=12; +latch origid destid weight seq linkid +1 10 12 NULL 0 10 +1 10 12 1 1 11 +1 10 12 1 2 12 +SELECT * FROM graph WHERE latch='1' AND origid=11 AND destid=10; +latch origid destid weight seq linkid +1 11 10 NULL 0 11 +1 11 10 1 1 12 +1 11 10 1 2 10 +SELECT * FROM graph WHERE latch='1' AND origid=11 AND destid=12; +latch origid destid weight seq linkid +1 11 12 NULL 0 11 +1 11 12 1 1 12 +SELECT * FROM graph WHERE latch='1' AND origid=12 AND destid=10; +latch origid destid weight seq linkid +1 12 10 NULL 0 12 +1 12 10 1 1 10 +SELECT * FROM graph WHERE latch='1' AND origid=12 AND destid=11; +latch origid destid weight seq linkid +1 12 11 NULL 0 12 +1 12 11 1 1 10 +1 12 11 1 2 11 +SELECT * FROM graph WHERE latch='1' AND origid=1; +latch origid destid weight seq linkid +1 1 NULL 2 4 4 +1 1 NULL 1 3 3 +1 1 NULL 1 2 2 +1 1 NULL 0 1 1 +SELECT * FROM graph WHERE latch='1' AND origid=2; +latch origid destid weight seq linkid +1 2 NULL 3 4 4 +1 2 NULL 2 3 3 +1 2 NULL 1 2 1 +1 2 NULL 0 1 2 +SELECT * FROM graph WHERE latch='1' AND origid=3; +latch origid destid weight seq linkid +1 3 NULL 2 4 2 +1 3 NULL 1 3 4 +1 3 NULL 1 2 1 +1 3 NULL 0 1 3 +SELECT * FROM graph WHERE latch='1' AND origid=4; +latch origid destid weight seq linkid +1 4 NULL 3 4 2 +1 4 NULL 2 3 1 +1 4 NULL 1 2 3 +1 4 NULL 0 1 4 +SELECT * FROM graph WHERE latch='1' AND origid=5; +latch origid destid weight seq linkid +1 5 NULL 1 3 7 +1 5 NULL 1 2 6 +1 5 NULL 0 1 5 +SELECT * FROM graph WHERE latch='1' AND origid=6; +latch origid destid weight seq linkid +1 6 NULL 2 3 7 +1 6 NULL 1 2 5 +1 6 NULL 0 1 6 +SELECT * FROM graph WHERE latch='1' AND origid=7; +latch origid destid weight seq linkid +1 7 NULL 0 1 7 +SELECT * FROM graph WHERE latch='1' AND origid=8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='1' AND origid=9; +latch origid destid weight seq linkid +1 9 NULL 0 1 9 +SELECT * FROM graph WHERE latch='1' AND origid=10; +latch origid destid weight seq linkid +1 10 NULL 2 3 12 +1 10 NULL 1 2 11 +1 10 NULL 0 1 10 +SELECT * FROM graph WHERE latch='1' AND origid=11; +latch origid destid weight seq linkid +1 11 NULL 2 3 10 +1 11 NULL 1 2 12 +1 11 NULL 0 1 11 +SELECT * FROM graph WHERE latch='1' AND origid=12; +latch origid destid weight seq linkid +1 12 NULL 2 3 11 +1 12 NULL 1 2 10 +1 12 NULL 0 1 12 +SELECT * FROM graph WHERE latch='1' AND origid=666; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='1' AND destid=1; +latch origid destid weight seq linkid +1 NULL 1 2 4 4 +1 NULL 1 1 3 3 +1 NULL 1 1 2 2 +1 NULL 1 0 1 1 +SELECT * FROM graph WHERE latch='1' AND destid=2; +latch origid destid weight seq linkid +1 NULL 2 3 4 4 +1 NULL 2 2 3 3 +1 NULL 2 1 2 1 +1 NULL 2 0 1 2 +SELECT * FROM graph WHERE latch='1' AND destid=3; +latch origid destid weight seq linkid +1 NULL 3 2 4 2 +1 NULL 3 1 3 4 +1 NULL 3 1 2 1 +1 NULL 3 0 1 3 +SELECT * FROM graph WHERE latch='1' AND destid=4; +latch origid destid weight seq linkid +1 NULL 4 3 4 2 +1 NULL 4 2 3 1 +1 NULL 4 1 2 3 +1 NULL 4 0 1 4 +SELECT * FROM graph WHERE latch='1' AND destid=5; +latch origid destid weight seq linkid +1 NULL 5 1 3 7 +1 NULL 5 1 2 6 +1 NULL 5 0 1 5 +SELECT * FROM graph WHERE latch='1' AND destid=6; +latch origid destid weight seq linkid +1 NULL 6 2 3 7 +1 NULL 6 1 2 5 +1 NULL 6 0 1 6 +SELECT * FROM graph WHERE latch='1' AND destid=7; +latch origid destid weight seq linkid +1 NULL 7 0 1 7 +SELECT * FROM graph WHERE latch='1' AND destid=8; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='1' AND destid=9; +latch origid destid weight seq linkid +1 NULL 9 0 1 9 +SELECT * FROM graph WHERE latch='1' AND destid=10; +latch origid destid weight seq linkid +1 NULL 10 2 3 12 +1 NULL 10 1 2 11 +1 NULL 10 0 1 10 +SELECT * FROM graph WHERE latch='1' AND destid=11; +latch origid destid weight seq linkid +1 NULL 11 2 3 10 +1 NULL 11 1 2 12 +1 NULL 11 0 1 11 +SELECT * FROM graph WHERE latch='1' AND destid=12; +latch origid destid weight seq linkid +1 NULL 12 2 3 11 +1 NULL 12 1 2 10 +1 NULL 12 0 1 12 +INSERT INTO graph_base(from_id, to_id) VALUES (11,13); +INSERT INTO graph_base(from_id, to_id) VALUES (10,14); +INSERT INTO graph_base(from_id, to_id) VALUES (14,13); +SELECT * FROM graph WHERE latch='dijkstras' AND origid=10 AND destid=13; +latch origid destid weight seq linkid +dijkstras 10 13 NULL 0 10 +dijkstras 10 13 1 1 11 +dijkstras 10 13 1 2 13 +DELETE FROM graph_base where from_id=10 and to_id=11; +INSERT INTO graph_base(from_id, to_id) VALUES (10,15); +INSERT INTO graph_base(from_id, to_id) VALUES (15,13); +SELECT * FROM graph WHERE latch='dijkstras' AND origid=10 AND destid=13; +latch origid destid weight seq linkid +dijkstras 10 13 NULL 0 10 +dijkstras 10 13 1 1 14 +dijkstras 10 13 1 2 13 +INSERT INTO graph_base(from_id, to_id) VALUES (10,11); +SELECT * FROM graph WHERE latch='dijkstras' AND origid=10 AND destid=13; +latch origid destid weight seq linkid +dijkstras 10 13 NULL 0 10 +dijkstras 10 13 1 1 11 +dijkstras 10 13 1 2 13 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1; +latch origid destid weight seq linkid +dijkstras 1 NULL 2 4 4 +dijkstras 1 NULL 1 3 3 +dijkstras 1 NULL 1 2 2 +dijkstras 1 NULL 0 1 1 +INSERT INTO graph_base(from_id, to_id) VALUES (21,22); +SELECT * FROM graph WHERE latch='dijkstras' AND origid=21; +latch origid destid weight seq linkid +dijkstras 21 NULL 1 2 22 +dijkstras 21 NULL 0 1 21 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=22; +latch origid destid weight seq linkid +dijkstras 22 NULL 0 1 22 +INSERT INTO graph_base(from_id, to_id) VALUES (4,17); +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1; +latch origid destid weight seq linkid +dijkstras 1 NULL 3 5 17 +dijkstras 1 NULL 2 4 4 +dijkstras 1 NULL 1 3 3 +dijkstras 1 NULL 1 2 2 +dijkstras 1 NULL 0 1 1 +INSERT INTO graph_base(from_id, to_id) VALUES (4,16); +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1; +latch origid destid weight seq linkid +dijkstras 1 NULL 3 6 17 +dijkstras 1 NULL 3 5 16 +dijkstras 1 NULL 2 4 4 +dijkstras 1 NULL 1 3 3 +dijkstras 1 NULL 1 2 2 +dijkstras 1 NULL 0 1 1 +INSERT INTO graph_base(from_id, to_id) VALUES (17,18); +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1; +latch origid destid weight seq linkid +dijkstras 1 NULL 4 7 18 +dijkstras 1 NULL 3 6 17 +dijkstras 1 NULL 3 5 16 +dijkstras 1 NULL 2 4 4 +dijkstras 1 NULL 1 3 3 +dijkstras 1 NULL 1 2 2 +dijkstras 1 NULL 0 1 1 +SELECT * FROM graph WHERE latch='dijkstras' AND destid=1; +latch origid destid weight seq linkid +dijkstras NULL 1 4 7 18 +dijkstras NULL 1 3 6 17 +dijkstras NULL 1 3 5 16 +dijkstras NULL 1 2 4 4 +dijkstras NULL 1 1 3 3 +dijkstras NULL 1 1 2 2 +dijkstras NULL 1 0 1 1 +# Now we add a connection from 4->6 +INSERT INTO graph_base (from_id,to_id) VALUES (4,6); +# And delete all references to node 5 +DELETE FROM graph_base WHERE from_id=5; +DELETE FROM graph_base WHERE from_id=3 AND to_id=5; +# which means there is a path in one direction only 1>3>4>6 +SELECT * FROM graph WHERE latch='dijkstras' AND origid=1 AND destid=6; +latch origid destid weight seq linkid +dijkstras 1 6 NULL 0 1 +dijkstras 1 6 1 1 3 +dijkstras 1 6 1 2 4 +dijkstras 1 6 1 3 6 +# but not 6>4>3>1 (so no result) +SELECT * FROM graph WHERE latch='dijkstras' AND origid=6 AND destid=1; +latch origid destid weight seq linkid +SELECT * FROM graph WHERE latch='1' AND origid=1 AND destid=6; +latch origid destid weight seq linkid +1 1 6 NULL 0 1 +1 1 6 1 1 3 +1 1 6 1 2 4 +1 1 6 1 3 6 +SELECT * FROM graph WHERE latch='1' AND origid=6 AND destid=1; +latch origid destid weight seq linkid +DELETE FROM graph_base; +FLUSH TABLES; +TRUNCATE TABLE graph_base; +DROP TABLE graph_base; +DROP TABLE graph; diff --git a/storage/oqgraph/mysql-test/oqgraph/general-innodb.test b/storage/oqgraph/mysql-test/oqgraph/general-innodb.test new file mode 100644 index 00000000000..4534eb41d38 --- /dev/null +++ b/storage/oqgraph/mysql-test/oqgraph/general-innodb.test @@ -0,0 +1,4 @@ +# This is a maintainer generated file. Generated at Wednesday 5 February 22:26:12 CST 2014. +-- source include/have_innodb.inc +--let $oqgraph_use_table_type= innodb +--source general.inc diff --git a/storage/oqgraph/mysql-test/oqgraph/basic.test b/storage/oqgraph/mysql-test/oqgraph/general.inc similarity index 99% rename from storage/oqgraph/mysql-test/oqgraph/basic.test rename to storage/oqgraph/mysql-test/oqgraph/general.inc index 088b69ef00a..7c49c72b4de 100644 --- a/storage/oqgraph/mysql-test/oqgraph/basic.test +++ b/storage/oqgraph/mysql-test/oqgraph/general.inc @@ -4,13 +4,15 @@ DROP TABLE IF EXISTS graph; DROP TABLE IF EXISTS graph2; --enable_warnings +--echo Performing OQGraph General test suite for ENGINE=$oqgraph_use_table_type + # Create the backing store -CREATE TABLE graph_base ( +eval CREATE TABLE graph_base ( from_id INT UNSIGNED NOT NULL, to_id INT UNSIGNED NOT NULL, PRIMARY KEY (from_id,to_id), INDEX (to_id) - ) ENGINE=MyISAM; + ) ENGINE= $oqgraph_use_table_type ; CREATE TABLE graph ( @@ -24,6 +26,9 @@ CREATE TABLE graph ( KEY (latch, destid, origid) USING HASH ) ENGINE=OQGRAPH DATA_TABLE='graph_base' ORIGID='from_id', DESTID='to_id'; +# Regression for MDEV-5891 +select * from graph; + #-- #-- ASCII art graph of this test data #-- +-->(2) diff --git a/storage/oqgraph/mysql-test/oqgraph/generate_backing_table_tests_suite.sh b/storage/oqgraph/mysql-test/oqgraph/generate_backing_table_tests_suite.sh new file mode 100755 index 00000000000..087b2b7089c --- /dev/null +++ b/storage/oqgraph/mysql-test/oqgraph/generate_backing_table_tests_suite.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +# This is a template fgenerator or repeating an identical suite of tests for each backing table storage engine +# It generates a set of .test files for the following, for example: +# general-myisam.test +# general-memory.test +# general-innodb.test +# (etc) +# +# We generate these files, because as a general rule the coverage should be identical per backing table engine +# but we might want to pick out and re-reun for an individual backing table engine +# otherwise we could use an MTR loop instead. + +# This is intended to be used by a maintainer; i.e. the resulting .test files are still committed to git. + +# Note on known storage engines: +# See https://mariadb.com/kb/en/information-schema-engines-table/ for a full list +# CSV - doesn't work with OQGraph, attempting to create backing table gives 'failed: 1069: Too many keys specified; max 0 keys allowed' +# BLACKHOLE - makes no sense... but we should make sure it doesnt crash +# FEDERATED, ARCHIVE - consider later + +ENGINES="MyISAM MEMORY Aria" + +for ENGINE in $ENGINES ; do + cat > general-$ENGINE.test < general-$ENGINE.test < $MGFILE +for ENGINE in $ENGINES $ENGINES2 ; do + echo mysql-test/mysql-test-run --record oqgraph.general-$ENGINE >> $MGFILE +done + diff --git a/storage/oqgraph/mysql-test/oqgraph/maintainer-general-record.sh b/storage/oqgraph/mysql-test/oqgraph/maintainer-general-record.sh new file mode 100755 index 00000000000..bc684015055 --- /dev/null +++ b/storage/oqgraph/mysql-test/oqgraph/maintainer-general-record.sh @@ -0,0 +1,5 @@ +# This is a maintainer generated file. Generated at Wednesday 5 February 22:26:12 CST 2014. +mysql-test/mysql-test-run --record oqgraph.general-MyISAM +mysql-test/mysql-test-run --record oqgraph.general-MEMORY +mysql-test/mysql-test-run --record oqgraph.general-Aria +mysql-test/mysql-test-run --record oqgraph.general-innodb diff --git a/storage/oqgraph/mysql-test/oqgraph/regression_mdev5996.inc b/storage/oqgraph/mysql-test/oqgraph/regression_mdev5996.inc new file mode 100644 index 00000000000..c0e4aa752fb --- /dev/null +++ b/storage/oqgraph/mysql-test/oqgraph/regression_mdev5996.inc @@ -0,0 +1,53 @@ +# Regression test for https://mariadb.atlassian.net/browse/MDEV-5996 +--echo Performing OQGraph regression test mdev5996 - using db=`$oqgraph_database_name`, table=`$oqgraph_table_name` + +--disable_warnings +use test; +if ($oqgraph_database_name) { + eval drop database if exists `$oqgraph_database_name` ; + eval create database `$oqgraph_database_name` ; + eval use `$oqgraph_database_name` ; +} +eval drop table if exists `$oqgraph_table_name` ; +drop table if exists vvvvvvv_hhhhhhh; +--enable_warnings + +eval CREATE TABLE `$oqgraph_table_name` ( + `version` varchar(10) NOT NULL, + `updateJSON` mediumtext, + `prevVersion` varchar(10) NOT NULL, + `nodeID` bigint(20) unsigned NOT NULL DEFAULT '0', + `prevNodeID` bigint(20) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`prevNodeID`,`nodeID`), + KEY `prevVersion` (`prevVersion`) USING BTREE, + KEY `version` (`version`) USING BTREE, + KEY `nodeID` (`nodeID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +eval insert into `$oqgraph_table_name` values ( 'x', 'y', 'z', 0, 0); + +eval select * from `$oqgraph_table_name`; + +eval CREATE TABLE IF NOT EXISTS vvvvvvv_hhhhhhh ( + latch VARCHAR(32) NULL, + origid BIGINT UNSIGNED NULL, + destid BIGINT UNSIGNED NULL, + weight DOUBLE NULL, + seq BIGINT UNSIGNED NULL, + linkid BIGINT UNSIGNED NULL, + KEY (latch, origid, destid) USING HASH, + KEY (latch, destid, origid) USING HASH +) ENGINE=OQGRAPH + data_table='$oqgraph_table_name' + origid='prevNodeID' + destid='nodeID'; + +select * from vvvvvvv_hhhhhhh; + +eval drop table if exists `$oqgraph_table_name`; +drop table if exists vvvvvvv_hhhhhhh; + +if ($oqgraph_database_name) { + eval drop database if exists `$oqgraph_database_name`; +} + diff --git a/storage/oqgraph/mysql-test/oqgraph/regression_mdev5996.result b/storage/oqgraph/mysql-test/oqgraph/regression_mdev5996.result new file mode 100644 index 00000000000..a639a185ec2 --- /dev/null +++ b/storage/oqgraph/mysql-test/oqgraph/regression_mdev5996.result @@ -0,0 +1,283 @@ +Performing OQGraph regression test mdev5996 - using db=``, table=`999999999` +use test; +drop table if exists `999999999` ; +drop table if exists vvvvvvv_hhhhhhh; +CREATE TABLE `999999999` ( +`version` varchar(10) NOT NULL, +`updateJSON` mediumtext, +`prevVersion` varchar(10) NOT NULL, +`nodeID` bigint(20) unsigned NOT NULL DEFAULT '0', +`prevNodeID` bigint(20) unsigned NOT NULL DEFAULT '0', +PRIMARY KEY (`prevNodeID`,`nodeID`), +KEY `prevVersion` (`prevVersion`) USING BTREE, +KEY `version` (`version`) USING BTREE, +KEY `nodeID` (`nodeID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +insert into `999999999` values ( 'x', 'y', 'z', 0, 0); +select * from `999999999`; +version updateJSON prevVersion nodeID prevNodeID +x y z 0 0 +CREATE TABLE IF NOT EXISTS vvvvvvv_hhhhhhh ( +latch VARCHAR(32) NULL, +origid BIGINT UNSIGNED NULL, +destid BIGINT UNSIGNED NULL, +weight DOUBLE NULL, +seq BIGINT UNSIGNED NULL, +linkid BIGINT UNSIGNED NULL, +KEY (latch, origid, destid) USING HASH, +KEY (latch, destid, origid) USING HASH +) ENGINE=OQGRAPH +data_table='999999999' + origid='prevNodeID' + destid='nodeID'; +select * from vvvvvvv_hhhhhhh; +latch origid destid weight seq linkid +NULL 0 0 1 NULL NULL +drop table if exists `999999999`; +drop table if exists vvvvvvv_hhhhhhh; +Performing OQGraph regression test mdev5996 - using db=`1`, table=`999999999` +use test; +drop database if exists `1` ; +create database `1` ; +use `1` ; +drop table if exists `999999999` ; +drop table if exists vvvvvvv_hhhhhhh; +CREATE TABLE `999999999` ( +`version` varchar(10) NOT NULL, +`updateJSON` mediumtext, +`prevVersion` varchar(10) NOT NULL, +`nodeID` bigint(20) unsigned NOT NULL DEFAULT '0', +`prevNodeID` bigint(20) unsigned NOT NULL DEFAULT '0', +PRIMARY KEY (`prevNodeID`,`nodeID`), +KEY `prevVersion` (`prevVersion`) USING BTREE, +KEY `version` (`version`) USING BTREE, +KEY `nodeID` (`nodeID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +insert into `999999999` values ( 'x', 'y', 'z', 0, 0); +select * from `999999999`; +version updateJSON prevVersion nodeID prevNodeID +x y z 0 0 +CREATE TABLE IF NOT EXISTS vvvvvvv_hhhhhhh ( +latch VARCHAR(32) NULL, +origid BIGINT UNSIGNED NULL, +destid BIGINT UNSIGNED NULL, +weight DOUBLE NULL, +seq BIGINT UNSIGNED NULL, +linkid BIGINT UNSIGNED NULL, +KEY (latch, origid, destid) USING HASH, +KEY (latch, destid, origid) USING HASH +) ENGINE=OQGRAPH +data_table='999999999' + origid='prevNodeID' + destid='nodeID'; +select * from vvvvvvv_hhhhhhh; +latch origid destid weight seq linkid +NULL 0 0 1 NULL NULL +drop table if exists `999999999`; +drop table if exists vvvvvvv_hhhhhhh; +drop database if exists `1`; +Performing OQGraph regression test mdev5996 - using db=`1112222233_4444444`, table=`999999999` +use test; +drop database if exists `1112222233_4444444` ; +create database `1112222233_4444444` ; +use `1112222233_4444444` ; +drop table if exists `999999999` ; +drop table if exists vvvvvvv_hhhhhhh; +CREATE TABLE `999999999` ( +`version` varchar(10) NOT NULL, +`updateJSON` mediumtext, +`prevVersion` varchar(10) NOT NULL, +`nodeID` bigint(20) unsigned NOT NULL DEFAULT '0', +`prevNodeID` bigint(20) unsigned NOT NULL DEFAULT '0', +PRIMARY KEY (`prevNodeID`,`nodeID`), +KEY `prevVersion` (`prevVersion`) USING BTREE, +KEY `version` (`version`) USING BTREE, +KEY `nodeID` (`nodeID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +insert into `999999999` values ( 'x', 'y', 'z', 0, 0); +select * from `999999999`; +version updateJSON prevVersion nodeID prevNodeID +x y z 0 0 +CREATE TABLE IF NOT EXISTS vvvvvvv_hhhhhhh ( +latch VARCHAR(32) NULL, +origid BIGINT UNSIGNED NULL, +destid BIGINT UNSIGNED NULL, +weight DOUBLE NULL, +seq BIGINT UNSIGNED NULL, +linkid BIGINT UNSIGNED NULL, +KEY (latch, origid, destid) USING HASH, +KEY (latch, destid, origid) USING HASH +) ENGINE=OQGRAPH +data_table='999999999' + origid='prevNodeID' + destid='nodeID'; +select * from vvvvvvv_hhhhhhh; +latch origid destid weight seq linkid +NULL 0 0 1 NULL NULL +drop table if exists `999999999`; +drop table if exists vvvvvvv_hhhhhhh; +drop database if exists `1112222233_4444444`; +Performing OQGraph regression test mdev5996 - using db=`1112222233_44444444`, table=`999999999` +use test; +drop database if exists `1112222233_44444444` ; +create database `1112222233_44444444` ; +use `1112222233_44444444` ; +drop table if exists `999999999` ; +drop table if exists vvvvvvv_hhhhhhh; +CREATE TABLE `999999999` ( +`version` varchar(10) NOT NULL, +`updateJSON` mediumtext, +`prevVersion` varchar(10) NOT NULL, +`nodeID` bigint(20) unsigned NOT NULL DEFAULT '0', +`prevNodeID` bigint(20) unsigned NOT NULL DEFAULT '0', +PRIMARY KEY (`prevNodeID`,`nodeID`), +KEY `prevVersion` (`prevVersion`) USING BTREE, +KEY `version` (`version`) USING BTREE, +KEY `nodeID` (`nodeID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +insert into `999999999` values ( 'x', 'y', 'z', 0, 0); +select * from `999999999`; +version updateJSON prevVersion nodeID prevNodeID +x y z 0 0 +CREATE TABLE IF NOT EXISTS vvvvvvv_hhhhhhh ( +latch VARCHAR(32) NULL, +origid BIGINT UNSIGNED NULL, +destid BIGINT UNSIGNED NULL, +weight DOUBLE NULL, +seq BIGINT UNSIGNED NULL, +linkid BIGINT UNSIGNED NULL, +KEY (latch, origid, destid) USING HASH, +KEY (latch, destid, origid) USING HASH +) ENGINE=OQGRAPH +data_table='999999999' + origid='prevNodeID' + destid='nodeID'; +select * from vvvvvvv_hhhhhhh; +latch origid destid weight seq linkid +NULL 0 0 1 NULL NULL +drop table if exists `999999999`; +drop table if exists vvvvvvv_hhhhhhh; +drop database if exists `1112222233_44444444`; +Performing OQGraph regression test mdev5996 - using db=`1112222233_444444444`, table=`999999999` +use test; +drop database if exists `1112222233_444444444` ; +create database `1112222233_444444444` ; +use `1112222233_444444444` ; +drop table if exists `999999999` ; +drop table if exists vvvvvvv_hhhhhhh; +CREATE TABLE `999999999` ( +`version` varchar(10) NOT NULL, +`updateJSON` mediumtext, +`prevVersion` varchar(10) NOT NULL, +`nodeID` bigint(20) unsigned NOT NULL DEFAULT '0', +`prevNodeID` bigint(20) unsigned NOT NULL DEFAULT '0', +PRIMARY KEY (`prevNodeID`,`nodeID`), +KEY `prevVersion` (`prevVersion`) USING BTREE, +KEY `version` (`version`) USING BTREE, +KEY `nodeID` (`nodeID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +insert into `999999999` values ( 'x', 'y', 'z', 0, 0); +select * from `999999999`; +version updateJSON prevVersion nodeID prevNodeID +x y z 0 0 +CREATE TABLE IF NOT EXISTS vvvvvvv_hhhhhhh ( +latch VARCHAR(32) NULL, +origid BIGINT UNSIGNED NULL, +destid BIGINT UNSIGNED NULL, +weight DOUBLE NULL, +seq BIGINT UNSIGNED NULL, +linkid BIGINT UNSIGNED NULL, +KEY (latch, origid, destid) USING HASH, +KEY (latch, destid, origid) USING HASH +) ENGINE=OQGRAPH +data_table='999999999' + origid='prevNodeID' + destid='nodeID'; +select * from vvvvvvv_hhhhhhh; +latch origid destid weight seq linkid +NULL 0 0 1 NULL NULL +drop table if exists `999999999`; +drop table if exists vvvvvvv_hhhhhhh; +drop database if exists `1112222233_444444444`; +Performing OQGraph regression test mdev5996 - using db=`1112222233_444444444`, table=`99999999` +use test; +drop database if exists `1112222233_444444444` ; +create database `1112222233_444444444` ; +use `1112222233_444444444` ; +drop table if exists `99999999` ; +drop table if exists vvvvvvv_hhhhhhh; +CREATE TABLE `99999999` ( +`version` varchar(10) NOT NULL, +`updateJSON` mediumtext, +`prevVersion` varchar(10) NOT NULL, +`nodeID` bigint(20) unsigned NOT NULL DEFAULT '0', +`prevNodeID` bigint(20) unsigned NOT NULL DEFAULT '0', +PRIMARY KEY (`prevNodeID`,`nodeID`), +KEY `prevVersion` (`prevVersion`) USING BTREE, +KEY `version` (`version`) USING BTREE, +KEY `nodeID` (`nodeID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +insert into `99999999` values ( 'x', 'y', 'z', 0, 0); +select * from `99999999`; +version updateJSON prevVersion nodeID prevNodeID +x y z 0 0 +CREATE TABLE IF NOT EXISTS vvvvvvv_hhhhhhh ( +latch VARCHAR(32) NULL, +origid BIGINT UNSIGNED NULL, +destid BIGINT UNSIGNED NULL, +weight DOUBLE NULL, +seq BIGINT UNSIGNED NULL, +linkid BIGINT UNSIGNED NULL, +KEY (latch, origid, destid) USING HASH, +KEY (latch, destid, origid) USING HASH +) ENGINE=OQGRAPH +data_table='99999999' + origid='prevNodeID' + destid='nodeID'; +select * from vvvvvvv_hhhhhhh; +latch origid destid weight seq linkid +NULL 0 0 1 NULL NULL +drop table if exists `99999999`; +drop table if exists vvvvvvv_hhhhhhh; +drop database if exists `1112222233_444444444`; +Performing OQGraph regression test mdev5996 - using db=`1112222233_444444444`, table=`9999999999` +use test; +drop database if exists `1112222233_444444444` ; +create database `1112222233_444444444` ; +use `1112222233_444444444` ; +drop table if exists `9999999999` ; +drop table if exists vvvvvvv_hhhhhhh; +CREATE TABLE `9999999999` ( +`version` varchar(10) NOT NULL, +`updateJSON` mediumtext, +`prevVersion` varchar(10) NOT NULL, +`nodeID` bigint(20) unsigned NOT NULL DEFAULT '0', +`prevNodeID` bigint(20) unsigned NOT NULL DEFAULT '0', +PRIMARY KEY (`prevNodeID`,`nodeID`), +KEY `prevVersion` (`prevVersion`) USING BTREE, +KEY `version` (`version`) USING BTREE, +KEY `nodeID` (`nodeID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +insert into `9999999999` values ( 'x', 'y', 'z', 0, 0); +select * from `9999999999`; +version updateJSON prevVersion nodeID prevNodeID +x y z 0 0 +CREATE TABLE IF NOT EXISTS vvvvvvv_hhhhhhh ( +latch VARCHAR(32) NULL, +origid BIGINT UNSIGNED NULL, +destid BIGINT UNSIGNED NULL, +weight DOUBLE NULL, +seq BIGINT UNSIGNED NULL, +linkid BIGINT UNSIGNED NULL, +KEY (latch, origid, destid) USING HASH, +KEY (latch, destid, origid) USING HASH +) ENGINE=OQGRAPH +data_table='9999999999' + origid='prevNodeID' + destid='nodeID'; +select * from vvvvvvv_hhhhhhh; +latch origid destid weight seq linkid +NULL 0 0 1 NULL NULL +drop table if exists `9999999999`; +drop table if exists vvvvvvv_hhhhhhh; +drop database if exists `1112222233_444444444`; diff --git a/storage/oqgraph/mysql-test/oqgraph/regression_mdev5996.test b/storage/oqgraph/mysql-test/oqgraph/regression_mdev5996.test new file mode 100644 index 00000000000..e5d04ef357d --- /dev/null +++ b/storage/oqgraph/mysql-test/oqgraph/regression_mdev5996.test @@ -0,0 +1,33 @@ +# Regression test for https://mariadb.atlassian.net/browse/MDEV-5996 +# MidSchipDB_unstable +--let $oqgraph_table_name= 999999999 + +--let $oqgraph_database_name= +--source regression_mdev5996.inc + +--let $oqgraph_database_name= 1 +--source regression_mdev5996.inc + +# Various cases - although actual bug was a broken zero termination +# name of backing store shorter, same and longer than table + +--let $oqgraph_database_name= 1112222233_4444444 +--source regression_mdev5996.inc + +--let $oqgraph_database_name= 1112222233_44444444 +--source regression_mdev5996.inc + +--let $oqgraph_database_name= 1112222233_444444444 +--source regression_mdev5996.inc + +--let $oqgraph_table_name= 99999999 +--source regression_mdev5996.inc + +--let $oqgraph_table_name= 9999999999 +--source regression_mdev5996.inc + +# Fails: + +# 1/9999 +# test/99999999 +# 1112222233_444444444/999999999 diff --git a/storage/oqgraph/oqgraph_shim.h b/storage/oqgraph/oqgraph_shim.h index b69fe1ae6eb..6ea9d10631f 100644 --- a/storage/oqgraph/oqgraph_shim.h +++ b/storage/oqgraph/oqgraph_shim.h @@ -184,6 +184,10 @@ namespace oqgraph3 typedef edge_info key_type; typedef boost::readable_property_map_tag category; edge_weight_property_map(const graph& g) : _g(g) { } + friend inline reference + get(const edge_weight_property_map& p, const key_type& key) + { return key.weight(); } + const graph& _g; }; @@ -436,16 +440,6 @@ namespace boost const oqgraph3::graph& g) { return property_map::const_type(g); } - inline property_map< - oqgraph3::graph, - edge_weight_t>::const_type::reference - get(const property_map::const_type& p, - const property_map< - oqgraph3::graph, - edge_weight_t>::const_type::key_type& key) - { return key.weight(); } - inline property_map< oqgraph3::graph, edge_index_t>::const_type::reference diff --git a/storage/tokudb/hatoku_hton.cc b/storage/tokudb/hatoku_hton.cc index 538f6c936d2..0257e68de1b 100644 --- a/storage/tokudb/hatoku_hton.cc +++ b/storage/tokudb/hatoku_hton.cc @@ -2399,7 +2399,7 @@ maria_declare_plugin(tokudb) toku_global_status_variables_export, /* status variables */ tokudb_system_variables, /* system variables */ TOKUDB_PLUGIN_VERSION_STR, /* string version */ - MariaDB_PLUGIN_MATURITY_GAMMA /* maturity */ + MariaDB_PLUGIN_MATURITY_STABLE /* maturity */ }, { MYSQL_INFORMATION_SCHEMA_PLUGIN, @@ -2414,7 +2414,7 @@ maria_declare_plugin(tokudb) NULL, /* status variables */ NULL, /* system variables */ TOKUDB_PLUGIN_VERSION_STR, /* string version */ - MariaDB_PLUGIN_MATURITY_GAMMA /* maturity */ + MariaDB_PLUGIN_MATURITY_STABLE /* maturity */ }, { MYSQL_INFORMATION_SCHEMA_PLUGIN, @@ -2429,7 +2429,7 @@ maria_declare_plugin(tokudb) NULL, /* status variables */ NULL, /* system variables */ TOKUDB_PLUGIN_VERSION_STR, /* string version */ - MariaDB_PLUGIN_MATURITY_GAMMA /* maturity */ + MariaDB_PLUGIN_MATURITY_STABLE /* maturity */ }, { MYSQL_INFORMATION_SCHEMA_PLUGIN, @@ -2444,7 +2444,7 @@ maria_declare_plugin(tokudb) NULL, /* status variables */ NULL, /* system variables */ TOKUDB_PLUGIN_VERSION_STR, /* string version */ - MariaDB_PLUGIN_MATURITY_GAMMA /* maturity */ + MariaDB_PLUGIN_MATURITY_STABLE /* maturity */ }, { MYSQL_INFORMATION_SCHEMA_PLUGIN, @@ -2459,7 +2459,7 @@ maria_declare_plugin(tokudb) NULL, /* status variables */ NULL, /* system variables */ TOKUDB_PLUGIN_VERSION_STR, /* string version */ - MariaDB_PLUGIN_MATURITY_GAMMA /* maturity */ + MariaDB_PLUGIN_MATURITY_STABLE /* maturity */ }, { MYSQL_INFORMATION_SCHEMA_PLUGIN, @@ -2474,7 +2474,7 @@ maria_declare_plugin(tokudb) NULL, /* status variables */ NULL, /* system variables */ TOKUDB_PLUGIN_VERSION_STR, /* string version */ - MariaDB_PLUGIN_MATURITY_GAMMA /* maturity */ + MariaDB_PLUGIN_MATURITY_STABLE /* maturity */ }, { MYSQL_INFORMATION_SCHEMA_PLUGIN, @@ -2489,7 +2489,7 @@ maria_declare_plugin(tokudb) NULL, /* status variables */ NULL, /* system variables */ TOKUDB_PLUGIN_VERSION_STR, /* string version */ - MariaDB_PLUGIN_MATURITY_GAMMA /* maturity */ + MariaDB_PLUGIN_MATURITY_STABLE /* maturity */ } maria_declare_plugin_end; diff --git a/storage/tokudb/mysql-test/tokudb/r/type_date.result b/storage/tokudb/mysql-test/tokudb/r/type_date.result index f34dc07130f..047dc6dc777 100644 --- a/storage/tokudb/mysql-test/tokudb/r/type_date.result +++ b/storage/tokudb/mysql-test/tokudb/r/type_date.result @@ -153,7 +153,7 @@ INSERT INTO t1 VALUES (1); INSERT INTO t1 VALUES (NULL); SELECT str_to_date( '', a ) FROM t1; str_to_date( '', a ) -0000-00-00 00:00:00 +0000-00-00 00:00:00.000000 NULL DROP TABLE t1; CREATE TABLE t1 (a DATE, b int, PRIMARY KEY (a,b)); diff --git a/storage/tokudb/mysql-test/tokudb_mariadb/r/229cols.result b/storage/tokudb/mysql-test/tokudb_mariadb/r/229cols.result new file mode 100644 index 00000000000..7875f3ff7a7 --- /dev/null +++ b/storage/tokudb/mysql-test/tokudb_mariadb/r/229cols.result @@ -0,0 +1,465 @@ +create table t1( +col1 varchar(40), +col2 varchar(40), +col3 varchar(40), +col4 varchar(40), +col5 varchar(40), +col6 varchar(40), +col7 varchar(40), +col8 varchar(40), +col9 varchar(40), +col10 varchar(40), +col11 varchar(40), +col12 varchar(40), +col13 varchar(40), +col14 varchar(40), +col15 varchar(40), +col16 varchar(40), +col17 varchar(40), +col18 varchar(40), +col19 varchar(40), +col20 varchar(40), +col21 varchar(40), +col22 varchar(40), +col23 varchar(40), +col24 varchar(40), +col25 varchar(40), +col26 varchar(40), +col27 varchar(40), +col28 varchar(40), +col29 varchar(40), +col30 varchar(40), +col31 varchar(40), +col32 varchar(40), +col33 varchar(40), +col34 varchar(40), +col35 varchar(40), +col36 varchar(40), +col37 varchar(40), +col38 varchar(40), +col39 varchar(40), +col40 varchar(40), +col41 varchar(40), +col42 varchar(40), +col43 varchar(40), +col44 varchar(40), +col45 varchar(40), +col46 varchar(40), +col47 varchar(40), +col48 varchar(40), +col49 varchar(40), +col50 varchar(40), +col51 varchar(40), +col52 varchar(40), +col53 varchar(40), +col54 varchar(40), +col55 varchar(40), +col56 varchar(40), +col57 varchar(40), +col58 varchar(40), +col59 varchar(40), +col60 varchar(40), +col61 varchar(40), +col62 varchar(40), +col63 varchar(40), +col64 varchar(40), +col65 varchar(40), +col66 varchar(40), +col67 varchar(40), +col68 varchar(40), +col69 varchar(40), +col70 varchar(40), +col71 varchar(40), +col72 varchar(40), +col73 varchar(40), +col74 varchar(40), +col75 varchar(40), +col76 varchar(40), +col77 varchar(40), +col78 varchar(40), +col79 varchar(40), +col80 varchar(40), +col81 varchar(40), +col82 varchar(40), +col83 varchar(40), +col84 varchar(40), +col85 varchar(40), +col86 varchar(40), +col87 varchar(40), +col88 varchar(40), +col89 varchar(40), +col90 varchar(40), +col91 varchar(40), +col92 varchar(40), +col93 varchar(40), +col94 varchar(40), +col95 varchar(40), +col96 varchar(40), +col97 varchar(40), +col98 varchar(40), +col99 varchar(40), +col100 varchar(40), +col101 varchar(40), +col102 varchar(40), +col103 varchar(40), +col104 varchar(40), +col105 varchar(40), +col106 varchar(40), +col107 varchar(40), +col108 varchar(40), +col109 varchar(40), +col110 varchar(40), +col111 varchar(40), +col112 varchar(40), +col113 varchar(40), +col114 varchar(40), +col115 varchar(40), +col116 varchar(40), +col117 varchar(40), +col118 varchar(40), +col119 varchar(40), +col120 varchar(40), +col121 varchar(40), +col122 varchar(40), +col123 varchar(40), +col124 varchar(40), +col125 varchar(40), +col126 varchar(40), +col127 varchar(40), +col128 varchar(40), +col129 varchar(40), +col130 varchar(40), +col131 varchar(40), +col132 varchar(40), +col133 varchar(40), +col134 varchar(40), +col135 varchar(40), +col136 varchar(40), +col137 varchar(40), +col138 varchar(40), +col139 varchar(40), +col140 varchar(40), +col141 varchar(40), +col142 varchar(40), +col143 varchar(40), +col144 varchar(40), +col145 varchar(40), +col146 varchar(40), +col147 varchar(40), +col148 varchar(40), +col149 varchar(40), +col150 varchar(40), +col151 varchar(40), +col152 varchar(40), +col153 varchar(40), +col154 varchar(40), +col155 varchar(40), +col156 varchar(40), +col157 varchar(40), +col158 varchar(40), +col159 varchar(40), +col160 varchar(40), +col161 varchar(40), +col162 varchar(40), +col163 varchar(40), +col164 varchar(40), +col165 varchar(40), +col166 varchar(40), +col167 varchar(40), +col168 varchar(40), +col169 varchar(40), +col170 varchar(40), +col171 varchar(40), +col172 varchar(40), +col173 varchar(40), +col174 varchar(40), +col175 varchar(40), +col176 varchar(40), +col177 varchar(40), +col178 varchar(40), +col179 varchar(40), +col180 varchar(40), +col181 varchar(40), +col182 varchar(40), +col183 varchar(40), +col184 varchar(40), +col185 varchar(40), +col186 varchar(40), +col187 varchar(40), +col188 varchar(40), +col189 varchar(40), +col190 varchar(40), +col191 varchar(40), +col192 varchar(40), +col193 varchar(40), +col194 varchar(40), +col195 varchar(40), +col196 varchar(40), +col197 varchar(40), +col198 varchar(40), +col199 varchar(40), +col200 varchar(40), +col201 varchar(40), +col202 varchar(40), +col203 varchar(40), +col204 varchar(40), +col205 varchar(40), +col206 varchar(40), +col207 varchar(40), +col208 varchar(40), +col209 varchar(40), +col210 varchar(40), +col211 varchar(40), +col212 varchar(40), +col213 varchar(40), +col214 varchar(40), +col215 varchar(40), +col216 varchar(40), +col217 varchar(40), +col218 varchar(40), +col219 varchar(40), +col220 varchar(40), +col221 varchar(40), +col222 varchar(40), +col223 varchar(40), +col224 varchar(40), +col225 varchar(40), +col226 varchar(40), +col227 varchar(40), +col228 varchar(40), +col229 varchar(40) +) engine=TokuDB; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `col1` varchar(40) DEFAULT NULL, + `col2` varchar(40) DEFAULT NULL, + `col3` varchar(40) DEFAULT NULL, + `col4` varchar(40) DEFAULT NULL, + `col5` varchar(40) DEFAULT NULL, + `col6` varchar(40) DEFAULT NULL, + `col7` varchar(40) DEFAULT NULL, + `col8` varchar(40) DEFAULT NULL, + `col9` varchar(40) DEFAULT NULL, + `col10` varchar(40) DEFAULT NULL, + `col11` varchar(40) DEFAULT NULL, + `col12` varchar(40) DEFAULT NULL, + `col13` varchar(40) DEFAULT NULL, + `col14` varchar(40) DEFAULT NULL, + `col15` varchar(40) DEFAULT NULL, + `col16` varchar(40) DEFAULT NULL, + `col17` varchar(40) DEFAULT NULL, + `col18` varchar(40) DEFAULT NULL, + `col19` varchar(40) DEFAULT NULL, + `col20` varchar(40) DEFAULT NULL, + `col21` varchar(40) DEFAULT NULL, + `col22` varchar(40) DEFAULT NULL, + `col23` varchar(40) DEFAULT NULL, + `col24` varchar(40) DEFAULT NULL, + `col25` varchar(40) DEFAULT NULL, + `col26` varchar(40) DEFAULT NULL, + `col27` varchar(40) DEFAULT NULL, + `col28` varchar(40) DEFAULT NULL, + `col29` varchar(40) DEFAULT NULL, + `col30` varchar(40) DEFAULT NULL, + `col31` varchar(40) DEFAULT NULL, + `col32` varchar(40) DEFAULT NULL, + `col33` varchar(40) DEFAULT NULL, + `col34` varchar(40) DEFAULT NULL, + `col35` varchar(40) DEFAULT NULL, + `col36` varchar(40) DEFAULT NULL, + `col37` varchar(40) DEFAULT NULL, + `col38` varchar(40) DEFAULT NULL, + `col39` varchar(40) DEFAULT NULL, + `col40` varchar(40) DEFAULT NULL, + `col41` varchar(40) DEFAULT NULL, + `col42` varchar(40) DEFAULT NULL, + `col43` varchar(40) DEFAULT NULL, + `col44` varchar(40) DEFAULT NULL, + `col45` varchar(40) DEFAULT NULL, + `col46` varchar(40) DEFAULT NULL, + `col47` varchar(40) DEFAULT NULL, + `col48` varchar(40) DEFAULT NULL, + `col49` varchar(40) DEFAULT NULL, + `col50` varchar(40) DEFAULT NULL, + `col51` varchar(40) DEFAULT NULL, + `col52` varchar(40) DEFAULT NULL, + `col53` varchar(40) DEFAULT NULL, + `col54` varchar(40) DEFAULT NULL, + `col55` varchar(40) DEFAULT NULL, + `col56` varchar(40) DEFAULT NULL, + `col57` varchar(40) DEFAULT NULL, + `col58` varchar(40) DEFAULT NULL, + `col59` varchar(40) DEFAULT NULL, + `col60` varchar(40) DEFAULT NULL, + `col61` varchar(40) DEFAULT NULL, + `col62` varchar(40) DEFAULT NULL, + `col63` varchar(40) DEFAULT NULL, + `col64` varchar(40) DEFAULT NULL, + `col65` varchar(40) DEFAULT NULL, + `col66` varchar(40) DEFAULT NULL, + `col67` varchar(40) DEFAULT NULL, + `col68` varchar(40) DEFAULT NULL, + `col69` varchar(40) DEFAULT NULL, + `col70` varchar(40) DEFAULT NULL, + `col71` varchar(40) DEFAULT NULL, + `col72` varchar(40) DEFAULT NULL, + `col73` varchar(40) DEFAULT NULL, + `col74` varchar(40) DEFAULT NULL, + `col75` varchar(40) DEFAULT NULL, + `col76` varchar(40) DEFAULT NULL, + `col77` varchar(40) DEFAULT NULL, + `col78` varchar(40) DEFAULT NULL, + `col79` varchar(40) DEFAULT NULL, + `col80` varchar(40) DEFAULT NULL, + `col81` varchar(40) DEFAULT NULL, + `col82` varchar(40) DEFAULT NULL, + `col83` varchar(40) DEFAULT NULL, + `col84` varchar(40) DEFAULT NULL, + `col85` varchar(40) DEFAULT NULL, + `col86` varchar(40) DEFAULT NULL, + `col87` varchar(40) DEFAULT NULL, + `col88` varchar(40) DEFAULT NULL, + `col89` varchar(40) DEFAULT NULL, + `col90` varchar(40) DEFAULT NULL, + `col91` varchar(40) DEFAULT NULL, + `col92` varchar(40) DEFAULT NULL, + `col93` varchar(40) DEFAULT NULL, + `col94` varchar(40) DEFAULT NULL, + `col95` varchar(40) DEFAULT NULL, + `col96` varchar(40) DEFAULT NULL, + `col97` varchar(40) DEFAULT NULL, + `col98` varchar(40) DEFAULT NULL, + `col99` varchar(40) DEFAULT NULL, + `col100` varchar(40) DEFAULT NULL, + `col101` varchar(40) DEFAULT NULL, + `col102` varchar(40) DEFAULT NULL, + `col103` varchar(40) DEFAULT NULL, + `col104` varchar(40) DEFAULT NULL, + `col105` varchar(40) DEFAULT NULL, + `col106` varchar(40) DEFAULT NULL, + `col107` varchar(40) DEFAULT NULL, + `col108` varchar(40) DEFAULT NULL, + `col109` varchar(40) DEFAULT NULL, + `col110` varchar(40) DEFAULT NULL, + `col111` varchar(40) DEFAULT NULL, + `col112` varchar(40) DEFAULT NULL, + `col113` varchar(40) DEFAULT NULL, + `col114` varchar(40) DEFAULT NULL, + `col115` varchar(40) DEFAULT NULL, + `col116` varchar(40) DEFAULT NULL, + `col117` varchar(40) DEFAULT NULL, + `col118` varchar(40) DEFAULT NULL, + `col119` varchar(40) DEFAULT NULL, + `col120` varchar(40) DEFAULT NULL, + `col121` varchar(40) DEFAULT NULL, + `col122` varchar(40) DEFAULT NULL, + `col123` varchar(40) DEFAULT NULL, + `col124` varchar(40) DEFAULT NULL, + `col125` varchar(40) DEFAULT NULL, + `col126` varchar(40) DEFAULT NULL, + `col127` varchar(40) DEFAULT NULL, + `col128` varchar(40) DEFAULT NULL, + `col129` varchar(40) DEFAULT NULL, + `col130` varchar(40) DEFAULT NULL, + `col131` varchar(40) DEFAULT NULL, + `col132` varchar(40) DEFAULT NULL, + `col133` varchar(40) DEFAULT NULL, + `col134` varchar(40) DEFAULT NULL, + `col135` varchar(40) DEFAULT NULL, + `col136` varchar(40) DEFAULT NULL, + `col137` varchar(40) DEFAULT NULL, + `col138` varchar(40) DEFAULT NULL, + `col139` varchar(40) DEFAULT NULL, + `col140` varchar(40) DEFAULT NULL, + `col141` varchar(40) DEFAULT NULL, + `col142` varchar(40) DEFAULT NULL, + `col143` varchar(40) DEFAULT NULL, + `col144` varchar(40) DEFAULT NULL, + `col145` varchar(40) DEFAULT NULL, + `col146` varchar(40) DEFAULT NULL, + `col147` varchar(40) DEFAULT NULL, + `col148` varchar(40) DEFAULT NULL, + `col149` varchar(40) DEFAULT NULL, + `col150` varchar(40) DEFAULT NULL, + `col151` varchar(40) DEFAULT NULL, + `col152` varchar(40) DEFAULT NULL, + `col153` varchar(40) DEFAULT NULL, + `col154` varchar(40) DEFAULT NULL, + `col155` varchar(40) DEFAULT NULL, + `col156` varchar(40) DEFAULT NULL, + `col157` varchar(40) DEFAULT NULL, + `col158` varchar(40) DEFAULT NULL, + `col159` varchar(40) DEFAULT NULL, + `col160` varchar(40) DEFAULT NULL, + `col161` varchar(40) DEFAULT NULL, + `col162` varchar(40) DEFAULT NULL, + `col163` varchar(40) DEFAULT NULL, + `col164` varchar(40) DEFAULT NULL, + `col165` varchar(40) DEFAULT NULL, + `col166` varchar(40) DEFAULT NULL, + `col167` varchar(40) DEFAULT NULL, + `col168` varchar(40) DEFAULT NULL, + `col169` varchar(40) DEFAULT NULL, + `col170` varchar(40) DEFAULT NULL, + `col171` varchar(40) DEFAULT NULL, + `col172` varchar(40) DEFAULT NULL, + `col173` varchar(40) DEFAULT NULL, + `col174` varchar(40) DEFAULT NULL, + `col175` varchar(40) DEFAULT NULL, + `col176` varchar(40) DEFAULT NULL, + `col177` varchar(40) DEFAULT NULL, + `col178` varchar(40) DEFAULT NULL, + `col179` varchar(40) DEFAULT NULL, + `col180` varchar(40) DEFAULT NULL, + `col181` varchar(40) DEFAULT NULL, + `col182` varchar(40) DEFAULT NULL, + `col183` varchar(40) DEFAULT NULL, + `col184` varchar(40) DEFAULT NULL, + `col185` varchar(40) DEFAULT NULL, + `col186` varchar(40) DEFAULT NULL, + `col187` varchar(40) DEFAULT NULL, + `col188` varchar(40) DEFAULT NULL, + `col189` varchar(40) DEFAULT NULL, + `col190` varchar(40) DEFAULT NULL, + `col191` varchar(40) DEFAULT NULL, + `col192` varchar(40) DEFAULT NULL, + `col193` varchar(40) DEFAULT NULL, + `col194` varchar(40) DEFAULT NULL, + `col195` varchar(40) DEFAULT NULL, + `col196` varchar(40) DEFAULT NULL, + `col197` varchar(40) DEFAULT NULL, + `col198` varchar(40) DEFAULT NULL, + `col199` varchar(40) DEFAULT NULL, + `col200` varchar(40) DEFAULT NULL, + `col201` varchar(40) DEFAULT NULL, + `col202` varchar(40) DEFAULT NULL, + `col203` varchar(40) DEFAULT NULL, + `col204` varchar(40) DEFAULT NULL, + `col205` varchar(40) DEFAULT NULL, + `col206` varchar(40) DEFAULT NULL, + `col207` varchar(40) DEFAULT NULL, + `col208` varchar(40) DEFAULT NULL, + `col209` varchar(40) DEFAULT NULL, + `col210` varchar(40) DEFAULT NULL, + `col211` varchar(40) DEFAULT NULL, + `col212` varchar(40) DEFAULT NULL, + `col213` varchar(40) DEFAULT NULL, + `col214` varchar(40) DEFAULT NULL, + `col215` varchar(40) DEFAULT NULL, + `col216` varchar(40) DEFAULT NULL, + `col217` varchar(40) DEFAULT NULL, + `col218` varchar(40) DEFAULT NULL, + `col219` varchar(40) DEFAULT NULL, + `col220` varchar(40) DEFAULT NULL, + `col221` varchar(40) DEFAULT NULL, + `col222` varchar(40) DEFAULT NULL, + `col223` varchar(40) DEFAULT NULL, + `col224` varchar(40) DEFAULT NULL, + `col225` varchar(40) DEFAULT NULL, + `col226` varchar(40) DEFAULT NULL, + `col227` varchar(40) DEFAULT NULL, + `col228` varchar(40) DEFAULT NULL, + `col229` varchar(40) DEFAULT NULL +) ENGINE=TokuDB DEFAULT CHARSET=latin1 `compression`='tokudb_zlib' +drop table t1; diff --git a/storage/tokudb/mysql-test/tokudb_mariadb/t/229cols.test b/storage/tokudb/mysql-test/tokudb_mariadb/t/229cols.test new file mode 100644 index 00000000000..5ea0025c19c --- /dev/null +++ b/storage/tokudb/mysql-test/tokudb_mariadb/t/229cols.test @@ -0,0 +1,234 @@ +create table t1( + col1 varchar(40), + col2 varchar(40), + col3 varchar(40), + col4 varchar(40), + col5 varchar(40), + col6 varchar(40), + col7 varchar(40), + col8 varchar(40), + col9 varchar(40), + col10 varchar(40), + col11 varchar(40), + col12 varchar(40), + col13 varchar(40), + col14 varchar(40), + col15 varchar(40), + col16 varchar(40), + col17 varchar(40), + col18 varchar(40), + col19 varchar(40), + col20 varchar(40), + col21 varchar(40), + col22 varchar(40), + col23 varchar(40), + col24 varchar(40), + col25 varchar(40), + col26 varchar(40), + col27 varchar(40), + col28 varchar(40), + col29 varchar(40), + col30 varchar(40), + col31 varchar(40), + col32 varchar(40), + col33 varchar(40), + col34 varchar(40), + col35 varchar(40), + col36 varchar(40), + col37 varchar(40), + col38 varchar(40), + col39 varchar(40), + col40 varchar(40), + col41 varchar(40), + col42 varchar(40), + col43 varchar(40), + col44 varchar(40), + col45 varchar(40), + col46 varchar(40), + col47 varchar(40), + col48 varchar(40), + col49 varchar(40), + col50 varchar(40), + col51 varchar(40), + col52 varchar(40), + col53 varchar(40), + col54 varchar(40), + col55 varchar(40), + col56 varchar(40), + col57 varchar(40), + col58 varchar(40), + col59 varchar(40), + col60 varchar(40), + col61 varchar(40), + col62 varchar(40), + col63 varchar(40), + col64 varchar(40), + col65 varchar(40), + col66 varchar(40), + col67 varchar(40), + col68 varchar(40), + col69 varchar(40), + col70 varchar(40), + col71 varchar(40), + col72 varchar(40), + col73 varchar(40), + col74 varchar(40), + col75 varchar(40), + col76 varchar(40), + col77 varchar(40), + col78 varchar(40), + col79 varchar(40), + col80 varchar(40), + col81 varchar(40), + col82 varchar(40), + col83 varchar(40), + col84 varchar(40), + col85 varchar(40), + col86 varchar(40), + col87 varchar(40), + col88 varchar(40), + col89 varchar(40), + col90 varchar(40), + col91 varchar(40), + col92 varchar(40), + col93 varchar(40), + col94 varchar(40), + col95 varchar(40), + col96 varchar(40), + col97 varchar(40), + col98 varchar(40), + col99 varchar(40), + col100 varchar(40), + col101 varchar(40), + col102 varchar(40), + col103 varchar(40), + col104 varchar(40), + col105 varchar(40), + col106 varchar(40), + col107 varchar(40), + col108 varchar(40), + col109 varchar(40), + col110 varchar(40), + col111 varchar(40), + col112 varchar(40), + col113 varchar(40), + col114 varchar(40), + col115 varchar(40), + col116 varchar(40), + col117 varchar(40), + col118 varchar(40), + col119 varchar(40), + col120 varchar(40), + col121 varchar(40), + col122 varchar(40), + col123 varchar(40), + col124 varchar(40), + col125 varchar(40), + col126 varchar(40), + col127 varchar(40), + col128 varchar(40), + col129 varchar(40), + col130 varchar(40), + col131 varchar(40), + col132 varchar(40), + col133 varchar(40), + col134 varchar(40), + col135 varchar(40), + col136 varchar(40), + col137 varchar(40), + col138 varchar(40), + col139 varchar(40), + col140 varchar(40), + col141 varchar(40), + col142 varchar(40), + col143 varchar(40), + col144 varchar(40), + col145 varchar(40), + col146 varchar(40), + col147 varchar(40), + col148 varchar(40), + col149 varchar(40), + col150 varchar(40), + col151 varchar(40), + col152 varchar(40), + col153 varchar(40), + col154 varchar(40), + col155 varchar(40), + col156 varchar(40), + col157 varchar(40), + col158 varchar(40), + col159 varchar(40), + col160 varchar(40), + col161 varchar(40), + col162 varchar(40), + col163 varchar(40), + col164 varchar(40), + col165 varchar(40), + col166 varchar(40), + col167 varchar(40), + col168 varchar(40), + col169 varchar(40), + col170 varchar(40), + col171 varchar(40), + col172 varchar(40), + col173 varchar(40), + col174 varchar(40), + col175 varchar(40), + col176 varchar(40), + col177 varchar(40), + col178 varchar(40), + col179 varchar(40), + col180 varchar(40), + col181 varchar(40), + col182 varchar(40), + col183 varchar(40), + col184 varchar(40), + col185 varchar(40), + col186 varchar(40), + col187 varchar(40), + col188 varchar(40), + col189 varchar(40), + col190 varchar(40), + col191 varchar(40), + col192 varchar(40), + col193 varchar(40), + col194 varchar(40), + col195 varchar(40), + col196 varchar(40), + col197 varchar(40), + col198 varchar(40), + col199 varchar(40), + col200 varchar(40), + col201 varchar(40), + col202 varchar(40), + col203 varchar(40), + col204 varchar(40), + col205 varchar(40), + col206 varchar(40), + col207 varchar(40), + col208 varchar(40), + col209 varchar(40), + col210 varchar(40), + col211 varchar(40), + col212 varchar(40), + col213 varchar(40), + col214 varchar(40), + col215 varchar(40), + col216 varchar(40), + col217 varchar(40), + col218 varchar(40), + col219 varchar(40), + col220 varchar(40), + col221 varchar(40), + col222 varchar(40), + col223 varchar(40), + col224 varchar(40), + col225 varchar(40), + col226 varchar(40), + col227 varchar(40), + col228 varchar(40), + col229 varchar(40) +) engine=TokuDB; +show create table t1; +drop table t1; + diff --git a/storage/xtradb/CMakeLists.txt b/storage/xtradb/CMakeLists.txt index a8b2c405eab..b3751b269c3 100644 --- a/storage/xtradb/CMakeLists.txt +++ b/storage/xtradb/CMakeLists.txt @@ -400,16 +400,6 @@ IF(WITH_INNODB) SET(WITH_INNOBASE_STORAGE_ENGINE TRUE) ENDIF() -# On solaris, reduce symbol visibility, so loader does not mix -# the same symbols from builtin innodb and from shared one. -# Only required for old GCC (3.4.3) that does not support hidden visibility -IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_COMPILER_IS_GNUCC - AND NOT HAVE_VISIBILITY_HIDDEN) - SET(LINKER_SCRIPT "-Wl,-M${CMAKE_CURRENT_SOURCE_DIR}/plugin_exports") -ELSE() - SET(LINKER_SCRIPT) -ENDIF() - IF(XTRADB_OK) MYSQL_ADD_PLUGIN(xtradb ${INNOBASE_SOURCES} STORAGE_ENGINE DEFAULT diff --git a/storage/xtradb/api/api0api.cc b/storage/xtradb/api/api0api.cc index d2f1a468f25..c5299156d7a 100644 --- a/storage/xtradb/api/api0api.cc +++ b/storage/xtradb/api/api0api.cc @@ -3870,6 +3870,7 @@ ib_table_truncate( ib_err_t trunc_err; ib_trx_t ib_trx = NULL; ib_crsr_t ib_crsr = NULL; + ib_ulint_t memcached_sync = 0; ib_trx = ib_trx_begin(IB_TRX_SERIALIZABLE, true, false); @@ -3885,6 +3886,13 @@ ib_table_truncate( err = DB_TABLE_NOT_FOUND; } + /* Remember the memcached_sync_count and set it to 0, so the + truncate can be executed. */ + if (table != NULL && err == DB_SUCCESS) { + memcached_sync = table->memcached_sync_count; + table->memcached_sync_count = 0; + } + dict_mutex_exit_for_mysql(); if (err == DB_SUCCESS) { @@ -3910,6 +3918,15 @@ ib_table_truncate( ut_a(err == DB_SUCCESS); } + /* Set the memcached_sync_count back. */ + if (table != NULL && memcached_sync != 0) { + dict_mutex_enter_for_mysql(); + + table->memcached_sync_count = memcached_sync; + + dict_mutex_exit_for_mysql(); + } + return(trunc_err); } @@ -3972,3 +3989,51 @@ ib_cfg_get_cfg() return(cfg_status); } + +/*****************************************************************//** +Increase/decrease the memcached sync count of table to sync memcached +DML with SQL DDLs. +@return DB_SUCCESS or error number */ +UNIV_INTERN +ib_err_t +ib_cursor_set_memcached_sync( +/*=========================*/ + ib_crsr_t ib_crsr, /*!< in: cursor */ + ib_bool_t flag) /*!< in: true for increase */ +{ + const ib_cursor_t* cursor = (const ib_cursor_t*) ib_crsr; + row_prebuilt_t* prebuilt = cursor->prebuilt; + dict_table_t* table = prebuilt->table; + ib_err_t err = DB_SUCCESS; + + if (table != NULL) { + /* If memcached_sync_count is -1, means table is + doing DDL, we just return error. */ + if (table->memcached_sync_count == DICT_TABLE_IN_DDL) { + return(DB_ERROR); + } + + if (flag) { +#ifdef HAVE_ATOMIC_BUILTINS + os_atomic_increment_lint(&table->memcached_sync_count, 1); +#else + dict_mutex_enter_for_mysql(); + ++table->memcached_sync_count; + dict_mutex_exit_for_mysql(); +#endif + } else { +#ifdef HAVE_ATOMIC_BUILTINS + os_atomic_decrement_lint(&table->memcached_sync_count, 1); +#else + dict_mutex_enter_for_mysql(); + --table->memcached_sync_count; + dict_mutex_exit_for_mysql(); +#endif + ut_a(table->memcached_sync_count >= 0); + } + } else { + err = DB_TABLE_NOT_FOUND; + } + + return(err); +} diff --git a/storage/xtradb/btr/btr0cur.cc b/storage/xtradb/btr/btr0cur.cc index a180649fa1e..fb12aac18b1 100644 --- a/storage/xtradb/btr/btr0cur.cc +++ b/storage/xtradb/btr/btr0cur.cc @@ -2236,8 +2236,7 @@ btr_cur_optimistic_update( contain trx id and roll ptr fields */ ulint cmpl_info,/*!< in: compiler info on secondary index updates */ - que_thr_t* thr, /*!< in: query thread, or NULL if - appropriate flags are set */ + que_thr_t* thr, /*!< in: query thread */ trx_id_t trx_id, /*!< in: transaction id */ mtr_t* mtr) /*!< in/out: mini-transaction; if this is a secondary index, the caller must @@ -2537,8 +2536,7 @@ btr_cur_pessimistic_update( the values in update vector have no effect */ ulint cmpl_info,/*!< in: compiler info on secondary index updates */ - que_thr_t* thr, /*!< in: query thread, or NULL if - appropriate flags are set */ + que_thr_t* thr, /*!< in: query thread */ trx_id_t trx_id, /*!< in: transaction id */ mtr_t* mtr) /*!< in/out: mini-transaction; must be committed before latching any further pages */ diff --git a/storage/xtradb/buf/buf0buddy.cc b/storage/xtradb/buf/buf0buddy.cc index 3f8f339a81a..442ee80235f 100644 --- a/storage/xtradb/buf/buf0buddy.cc +++ b/storage/xtradb/buf/buf0buddy.cc @@ -545,10 +545,8 @@ buf_buddy_relocate( { buf_page_t* bpage; const ulint size = BUF_BUDDY_LOW << i; - ib_mutex_t* mutex; ulint space; ulint offset; - prio_rw_lock_t* hash_lock; ut_ad(mutex_own(&buf_pool->zip_free_mutex)); ut_ad(!mutex_own(&buf_pool->zip_mutex)); @@ -570,8 +568,13 @@ buf_buddy_relocate( ut_ad(space != BUF_BUDDY_STAMP_FREE); mutex_exit(&buf_pool->zip_free_mutex); - /* Lock page hash to prevent a relocation for the target page */ - bpage = buf_page_hash_get_s_locked(buf_pool, space, offset, &hash_lock); + + ulint fold = buf_page_address_fold(space, offset); + prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold); + + rw_lock_x_lock(hash_lock); + + bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); if (!bpage || bpage->zip.data != src) { /* The block has probably been freshly @@ -579,9 +582,8 @@ buf_buddy_relocate( added to buf_pool->page_hash yet. Obviously, it cannot be relocated. */ - if (bpage) { - rw_lock_s_unlock(hash_lock); - } + rw_lock_x_unlock(hash_lock); + mutex_enter(&buf_pool->zip_free_mutex); return(false); } @@ -592,7 +594,8 @@ buf_buddy_relocate( For the sake of simplicity, give up. */ ut_ad(page_zip_get_size(&bpage->zip) < size); - rw_lock_s_unlock(hash_lock); + rw_lock_x_unlock(hash_lock); + mutex_enter(&buf_pool->zip_free_mutex); return(false); } @@ -601,31 +604,44 @@ buf_buddy_relocate( contain uninitialized data. */ UNIV_MEM_ASSERT_W(src, size); - mutex = buf_page_get_mutex(bpage); + ib_mutex_t* block_mutex = buf_page_get_mutex(bpage); - mutex_enter(mutex); - - rw_lock_s_unlock(hash_lock); + mutex_enter(block_mutex); mutex_enter(&buf_pool->zip_free_mutex); if (buf_page_can_relocate(bpage)) { /* Relocate the compressed page. */ - ullint usec = ut_time_us(NULL); + ullint usec = ut_time_us(NULL); + ut_a(bpage->zip.data == src); - memcpy(dst, src, size); - bpage->zip.data = (page_zip_t*) dst; - mutex_exit(mutex); + + /* Note: This is potentially expensive, we need a better + solution here. We go with correctness for now. */ + ::memcpy(dst, src, size); + + bpage->zip.data = reinterpret_cast(dst); + + rw_lock_x_unlock(hash_lock); + + mutex_exit(block_mutex); + buf_buddy_mem_invalid( reinterpret_cast(src), i); buf_buddy_stat_t* buddy_stat = &buf_pool->buddy_stat[i]; - buddy_stat->relocated++; + + ++buddy_stat->relocated; + buddy_stat->relocated_usec += ut_time_us(NULL) - usec; + return(true); } - mutex_exit(mutex); + rw_lock_x_unlock(hash_lock); + + mutex_exit(block_mutex); + return(false); } diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc index 2ec25491f4c..69dcc4ce9cb 100644 --- a/storage/xtradb/buf/buf0buf.cc +++ b/storage/xtradb/buf/buf0buf.cc @@ -576,8 +576,11 @@ buf_page_is_corrupted( if (checksum_field1 == 0 && checksum_field2 == 0 && mach_read_from_4(read_buf + FIL_PAGE_LSN) == 0) { /* make sure that the page is really empty */ - ut_d(for (ulint i = 0; i < UNIV_PAGE_SIZE; i++) { - ut_a(read_buf[i] == 0); }); + for (ulint i = 0; i < UNIV_PAGE_SIZE; i++) { + if (read_buf[i] != 0) { + return(TRUE); + } + } return(FALSE); } @@ -1650,16 +1653,19 @@ buf_pool_watch_set( bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); - if (UNIV_LIKELY_NULL(bpage)) { + if (bpage != NULL) { page_found: if (!buf_pool_watch_is_sentinel(buf_pool, bpage)) { /* The page was loaded meanwhile. */ return(bpage); } + /* Add to an existing watch. */ - mutex_enter(&buf_pool->zip_mutex); - bpage->buf_fix_count++; - mutex_exit(&buf_pool->zip_mutex); +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_increment_uint32(&bpage->buf_fix_count, 1); +#else + ++bpage->buf_fix_count; +#endif /* PAGE_ATOMIC_REF_COUNT */ return(NULL); } @@ -1782,31 +1788,32 @@ buf_pool_watch_unset( buf_page_t* bpage; buf_pool_t* buf_pool = buf_pool_get(space, offset); ulint fold = buf_page_address_fold(space, offset); - prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, - fold); + prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold); rw_lock_x_lock(hash_lock); + /* The page must exist because buf_pool_watch_set() increments + buf_fix_count. */ + bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); - /* The page must exist because buf_pool_watch_set() - increments buf_fix_count. */ - ut_a(bpage); - if (UNIV_UNLIKELY(!buf_pool_watch_is_sentinel(buf_pool, bpage))) { - ib_mutex_t* mutex = buf_page_get_mutex(bpage); - - mutex_enter(mutex); - ut_a(bpage->buf_fix_count > 0); - bpage->buf_fix_count--; - mutex_exit(mutex); + if (!buf_pool_watch_is_sentinel(buf_pool, bpage)) { + buf_block_unfix(reinterpret_cast(bpage)); } else { - ut_a(bpage->buf_fix_count > 0); - mutex_enter(&buf_pool->zip_mutex); - if (UNIV_LIKELY(!--bpage->buf_fix_count)) { + ut_ad(bpage->buf_fix_count > 0); + +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_decrement_uint32(&bpage->buf_fix_count, 1); +#else + --bpage->buf_fix_count; +#endif /* PAGE_ATOMIC_REF_COUNT */ + + if (bpage->buf_fix_count == 0) { + mutex_enter(&buf_pool->zip_mutex); buf_pool_watch_remove(buf_pool, fold, bpage); + mutex_exit(&buf_pool->zip_mutex); } - mutex_exit(&buf_pool->zip_mutex); } rw_lock_x_unlock(hash_lock); @@ -1833,10 +1840,10 @@ buf_pool_watch_occurred( rw_lock_s_lock(hash_lock); - bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); /* The page must exist because buf_pool_watch_set() increments buf_fix_count. */ - ut_a(bpage); + bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); + ret = !buf_pool_watch_is_sentinel(buf_pool, bpage); rw_lock_s_unlock(hash_lock); @@ -2093,27 +2100,32 @@ err_exit: case BUF_BLOCK_READY_FOR_USE: case BUF_BLOCK_MEMORY: case BUF_BLOCK_REMOVE_HASH: - break; + ut_error; + case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_DIRTY: block_mutex = &buf_pool->zip_mutex; mutex_enter(block_mutex); - bpage->buf_fix_count++; +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_increment_uint32(&bpage->buf_fix_count, 1); +#else + ++bpage->buf_fix_count; +#endif /* PAGE_ATOMIC_REF_COUNT */ goto got_block; case BUF_BLOCK_FILE_PAGE: /* Discard the uncompressed page frame if possible. */ if (!discard_attempted) { rw_lock_s_unlock(hash_lock); - buf_block_try_discard_uncompressed(space, - offset); + buf_block_try_discard_uncompressed(space, offset); discard_attempted = TRUE; goto lookup; } block_mutex = &((buf_block_t*) bpage)->mutex; + mutex_enter(block_mutex); - buf_block_buf_fix_inc((buf_block_t*) bpage, - __FILE__, __LINE__); + + buf_block_buf_fix_inc((buf_block_t*) bpage, __FILE__, __LINE__); goto got_block; } @@ -2126,7 +2138,7 @@ got_block: rw_lock_s_unlock(hash_lock); #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG ut_a(!bpage->file_page_was_freed); -#endif +#endif /* defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG */ buf_page_set_accessed(bpage); @@ -2451,7 +2463,7 @@ buf_block_is_uncompressed( const buf_block_t* block) /*!< in: pointer to block, not dereferenced */ { - if (UNIV_UNLIKELY((((ulint) block) % sizeof *block) != 0)) { + if ((((ulint) block) % sizeof *block) != 0) { /* The pointer should be aligned. */ return(FALSE); } @@ -2481,6 +2493,70 @@ buf_debug_execute_is_force_flush() } #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ +/** +Wait for the block to be read in. +@param block The block to check +@param trx Transaction to account the I/Os to */ +static +void +buf_wait_for_read(buf_block_t* block, trx_t* trx) +{ + /* Note: For the PAGE_ATOMIC_REF_COUNT case: + + We are using the block->lock to check for IO state (and a dirty read). + We set the IO_READ state under the protection of the hash_lock + (and block->mutex). This is safe because another thread can only + access the block (and check for IO state) after the block has been + added to the page hashtable. */ + + if (buf_block_get_io_fix_unlocked(block) == BUF_IO_READ) { + + ib_uint64_t start_time; + ulint sec; + ulint ms; + + /* Wait until the read operation completes */ + + ib_mutex_t* mutex = buf_page_get_mutex(&block->page); + + if (UNIV_UNLIKELY(trx && trx->take_stats)) + { + ut_usectime(&sec, &ms); + start_time = (ib_uint64_t)sec * 1000000 + ms; + } else { + start_time = 0; + } + + for (;;) { + buf_io_fix io_fix; + + mutex_enter(mutex); + + io_fix = buf_block_get_io_fix(block); + + mutex_exit(mutex); + + if (io_fix == BUF_IO_READ) { + /* Wait by temporaly s-latch */ + rw_lock_s_lock(&block->lock); + rw_lock_s_unlock(&block->lock); + } else { + break; + } + } + + if (UNIV_UNLIKELY(start_time != 0)) + { + ut_usectime(&sec, &ms); + ib_uint64_t finish_time + = (ib_uint64_t)sec * 1000000 + ms; + trx->io_reads_wait_timer + += (ulint)(finish_time - start_time); + } + + } +} + /********************************************************************//** This is the general function used to get access to a database page. @return pointer to the block or NULL */ @@ -2505,15 +2581,11 @@ buf_page_get_gen( ulint fold; unsigned access_time; ulint fix_type; - ibool must_read; prio_rw_lock_t* hash_lock; - ib_mutex_t* block_mutex; ulint retries = 0; trx_t* trx = NULL; - ulint sec; - ulint ms; - ib_uint64_t start_time; - ib_uint64_t finish_time; + buf_block_t* fix_block; + ib_mutex_t* fix_mutex = NULL; buf_pool_t* buf_pool = buf_pool_get(space, offset); ut_ad(mtr); @@ -2553,7 +2625,9 @@ loop: block = guess; rw_lock_s_lock(hash_lock); - if (block) { + + if (block != NULL) { + /* If the guess is a compressed page descriptor that has been allocated by buf_page_alloc_descriptor(), it may have been freed by buf_relocate(). */ @@ -2591,10 +2665,10 @@ loop: if (UNIV_LIKELY_NULL(block)) { /* We can release hash_lock after we - acquire block_mutex to make sure that - no state change takes place. */ - block_mutex = buf_page_get_mutex(&block->page); - mutex_enter(block_mutex); + increment the fix count to make + sure that no state change takes place. */ + fix_block = block; + buf_block_fix(fix_block); /* Now safe to release page_hash mutex */ rw_lock_x_unlock(hash_lock); @@ -2649,48 +2723,60 @@ loop: ut_a(++buf_dbg_counter % 5771 || buf_validate()); #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ goto loop; + } else { + fix_block = block; } - - /* We can release hash_lock after we acquire block_mutex to - make sure that no state change takes place. */ - block_mutex = buf_page_get_mutex(&block->page); - mutex_enter(block_mutex); + buf_block_fix(fix_block); /* Now safe to release page_hash mutex */ rw_lock_s_unlock(hash_lock); got_block: + + fix_mutex = buf_page_get_mutex(&fix_block->page); + ut_ad(page_zip_get_size(&block->page.zip) == zip_size); - ut_ad(mutex_own(block_mutex)); - must_read = buf_block_get_io_fix(block) == BUF_IO_READ; + if (mode == BUF_GET_IF_IN_POOL || mode == BUF_PEEK_IF_IN_POOL) { - if (must_read && (mode == BUF_GET_IF_IN_POOL - || mode == BUF_PEEK_IF_IN_POOL)) { + bool must_read; - /* The page is being read to buffer pool, - but we cannot wait around for the read to - complete. */ -null_exit: - mutex_exit(block_mutex); + { + buf_page_t* fix_page = &fix_block->page; - return(NULL); + mutex_enter(fix_mutex); + + buf_io_fix io_fix = buf_page_get_io_fix(fix_page); + + must_read = (io_fix == BUF_IO_READ); + + mutex_exit(fix_mutex); + } + + if (must_read) { + /* The page is being read to buffer pool, + but we cannot wait around for the read to + complete. */ + buf_block_unfix(fix_block); + + return(NULL); + } } - if (UNIV_UNLIKELY(block->page.is_corrupt && + if (UNIV_UNLIKELY(fix_block->page.is_corrupt && srv_pass_corrupt_table <= 1)) { - mutex_exit(block_mutex); + buf_block_unfix(fix_block); return(NULL); } - switch (buf_block_get_state(block)) { + switch(buf_block_get_state(fix_block)) { buf_page_t* bpage; case BUF_BLOCK_FILE_PAGE: - ut_ad(block_mutex != &buf_pool->zip_mutex); + ut_ad(fix_mutex != &buf_pool->zip_mutex); break; case BUF_BLOCK_ZIP_PAGE: @@ -2700,19 +2786,24 @@ null_exit: adaptive hash index. There cannot be an adaptive hash index for a compressed-only page, so do not bother decompressing the page. */ - goto null_exit; + buf_block_unfix(fix_block); + + return(NULL); } bpage = &block->page; - ut_ad(block_mutex == &buf_pool->zip_mutex); + ut_ad(fix_mutex == &buf_pool->zip_mutex); + + /* Note: We have already buffer fixed this block. */ + if (bpage->buf_fix_count > 1 + || buf_page_get_io_fix_unlocked(bpage) != BUF_IO_NONE) { - if (bpage->buf_fix_count - || buf_page_get_io_fix(bpage) != BUF_IO_NONE) { /* This condition often occurs when the buffer is not buffer-fixed, but I/O-fixed by buf_page_init_for_read(). */ - mutex_exit(&buf_pool->zip_mutex); -wait_until_unfixed: + + buf_block_unfix(fix_block); + /* The block is buffer-fixed or I/O-fixed. Try again later. */ os_thread_sleep(WAIT_FOR_READ); @@ -2723,24 +2814,34 @@ wait_until_unfixed: /* Buffer-fix the block so that it cannot be evicted or relocated while we are attempting to allocate an uncompressed page. */ - bpage->buf_fix_count++; /* Allocate an uncompressed page. */ - mutex_exit(&buf_pool->zip_mutex); + block = buf_LRU_get_free_block(buf_pool); - ut_a(block); mutex_enter(&buf_pool->LRU_list_mutex); rw_lock_x_lock(hash_lock); + /* Buffer-fixing prevents the page_hash from changing. */ ut_ad(bpage == buf_page_hash_get_low( buf_pool, space, offset, fold)); - mutex_enter(&block->mutex); + buf_block_mutex_enter(block); + mutex_enter(&buf_pool->zip_mutex); - if (--bpage->buf_fix_count + ut_ad(fix_block->page.buf_fix_count > 0); + +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_decrement_uint32(&fix_block->page.buf_fix_count, 1); +#else + --fix_block->page.buf_fix_count; +#endif /* PAGE_ATOMIC_REF_COUNT */ + + fix_block = block; + + if (bpage->buf_fix_count > 0 || buf_page_get_io_fix(bpage) != BUF_IO_NONE) { mutex_exit(&buf_pool->zip_mutex); @@ -2753,23 +2854,31 @@ wait_until_unfixed: buf_LRU_block_free_non_file_page(block); mutex_exit(&buf_pool->LRU_list_mutex); rw_lock_x_unlock(hash_lock); - mutex_exit(&block->mutex); + buf_block_mutex_exit(block); - goto wait_until_unfixed; + /* Try again */ + goto loop; } /* Move the compressed page from bpage to block, and uncompress it. */ + /* Note: this is the uncompressed block and it is not + accessible by other threads yet because it is not in + any list or hash table */ buf_relocate(bpage, &block->page); + buf_block_init_low(block); + + /* Set after relocate(). */ + block->page.buf_fix_count = 1; + block->lock_hash_val = lock_rec_hash(space, offset); UNIV_MEM_DESC(&block->page.zip.data, - page_zip_get_size(&block->page.zip)); + page_zip_get_size(&block->page.zip)); - if (buf_page_get_state(&block->page) - == BUF_BLOCK_ZIP_PAGE) { + if (buf_page_get_state(&block->page) == BUF_BLOCK_ZIP_PAGE) { #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG UT_LIST_REMOVE(list, buf_pool->zip_clean, &block->page); @@ -2777,8 +2886,7 @@ wait_until_unfixed: ut_ad(!block->page.in_flush_list); } else { /* Relocate buf_pool->flush_list. */ - buf_flush_relocate_on_flush_list(bpage, - &block->page); + buf_flush_relocate_on_flush_list(bpage, &block->page); } /* Buffer-fix, I/O-fix, and X-latch the block @@ -2791,7 +2899,6 @@ wait_until_unfixed: mutex_exit(&buf_pool->LRU_list_mutex); - block->page.buf_fix_count = 1; buf_block_set_io_fix(block, BUF_IO_READ); rw_lock_x_lock_inline(&block->lock, 0, file, line); @@ -2802,7 +2909,9 @@ wait_until_unfixed: os_atomic_increment_ulint(&buf_pool->n_pend_unzip, 1); access_time = buf_page_is_accessed(&block->page); - mutex_exit(&block->mutex); + + buf_block_mutex_exit(block); + mutex_exit(&buf_pool->zip_mutex); buf_page_free_descriptor(bpage); @@ -2813,9 +2922,12 @@ wait_until_unfixed: /* Page checksum verification is already done when the page is read from disk. Hence page checksum verification is not necessary when decompressing the page. */ - ut_a(buf_zip_decompress(block, FALSE)); + { + bool success = buf_zip_decompress(block, FALSE); + ut_a(success); + } - if (UNIV_LIKELY(!recv_no_ibuf_operations)) { + if (!recv_no_ibuf_operations) { if (access_time) { #ifdef UNIV_IBUF_COUNT_DEBUG ut_a(ibuf_count_get(space, offset) == 0); @@ -2827,10 +2939,14 @@ wait_until_unfixed: } /* Unfix and unlatch the block. */ - mutex_enter(&block->mutex); - block->page.buf_fix_count--; - buf_block_set_io_fix(block, BUF_IO_NONE); + buf_block_mutex_enter(fix_block); + + buf_block_set_io_fix(fix_block, BUF_IO_NONE); + + buf_block_mutex_exit(fix_block); + os_atomic_decrement_ulint(&buf_pool->n_pend_unzip, 1); + rw_lock_x_unlock(&block->lock); break; @@ -2844,39 +2960,45 @@ wait_until_unfixed: break; } + ut_ad(block == fix_block); + ut_ad(fix_block->page.buf_fix_count > 0); + #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX)); ut_ad(!rw_lock_own(hash_lock, RW_LOCK_SHARED)); #endif /* UNIV_SYNC_DEBUG */ - ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); + ut_ad(buf_block_get_state(fix_block) == BUF_BLOCK_FILE_PAGE); #if UNIV_WORD_SIZE == 4 /* On 32-bit systems, there is no padding in buf_page_t. On other systems, Valgrind could complain about uninitialized pad bytes. */ - UNIV_MEM_ASSERT_RW(&block->page, sizeof block->page); + UNIV_MEM_ASSERT_RW(&fix_block->page, sizeof(fix_block->page)); #endif #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG if ((mode == BUF_GET_IF_IN_POOL || mode == BUF_GET_IF_IN_POOL_OR_WATCH) && (ibuf_debug || buf_debug_execute_is_force_flush())) { + /* Try to evict the block from the buffer pool, to use the insert buffer (change buffer) as much as possible. */ - /* To obey the latching order, release the - block->mutex before acquiring buf_pool->LRU_list_mutex. Protect - the block from changes by temporarily buffer-fixing it - for the time we are not holding block->mutex. */ - - buf_block_buf_fix_inc(block, file, line); - mutex_exit(&block->mutex); mutex_enter(&buf_pool->LRU_list_mutex); - mutex_enter(&block->mutex); - buf_block_buf_fix_dec(block); - if (buf_LRU_free_page(&block->page, true)) { - mutex_exit(&block->mutex); + buf_block_unfix(fix_block); + + /* Now we are only holding the buf_pool->LRU_list_mutex, + not block->mutex or hash_lock. Blocks cannot be + relocated or enter or exit the buf_pool while we + are holding the buf_pool->LRU_list_mutex. */ + + fix_mutex = buf_page_get_mutex(&fix_block->page); + mutex_enter(fix_mutex); + + if (buf_LRU_free_page(&fix_block->page, true)) { + + mutex_exit(fix_mutex); rw_lock_x_lock(hash_lock); if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) { @@ -2892,7 +3014,7 @@ wait_until_unfixed: rw_lock_x_unlock(hash_lock); - if (UNIV_LIKELY_NULL(block)) { + if (block != NULL) { /* Either the page has been read in or a watch was set on that in the window where we released the buf_pool::mutex @@ -2906,111 +3028,108 @@ wait_until_unfixed: "innodb_change_buffering_debug evict %u %u\n", (unsigned) space, (unsigned) offset); return(NULL); - } else { - - mutex_exit(&buf_pool->LRU_list_mutex); } - if (buf_flush_page_try(buf_pool, block)) { + if (buf_flush_page_try(buf_pool, fix_block)) { fprintf(stderr, "innodb_change_buffering_debug flush %u %u\n", (unsigned) space, (unsigned) offset); - guess = block; + guess = fix_block; goto loop; } + mutex_exit(&buf_pool->LRU_list_mutex); + + buf_block_mutex_exit(fix_block); + + buf_block_fix(fix_block); + /* Failed to evict the page; change it directly */ } #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ - buf_block_buf_fix_inc(block, file, line); + ut_ad(fix_block->page.buf_fix_count > 0); + +#ifdef UNIV_SYNC_DEBUG + /* We have already buffer fixed the page, and we are committed to + returning this page to the caller. Register for debugging. */ + { + ibool ret; + ret = rw_lock_s_lock_nowait(&fix_block->debug_latch, file, line); + ut_a(ret); + } +#endif /* UNIV_SYNC_DEBUG */ + #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG ut_a(mode == BUF_GET_POSSIBLY_FREED - || !block->page.file_page_was_freed); + || !fix_block->page.file_page_was_freed); #endif /* Check if this is the first access to the page */ - access_time = buf_page_is_accessed(&block->page); + access_time = buf_page_is_accessed(&fix_block->page); - buf_page_set_accessed(&block->page); + /* This is a heuristic and we don't care about ordering issues. */ + if (access_time == 0) { + buf_block_mutex_enter(fix_block); - mutex_exit(&block->mutex); + buf_page_set_accessed(&fix_block->page); + + buf_block_mutex_exit(fix_block); + } if (mode != BUF_PEEK_IF_IN_POOL) { - buf_page_make_young_if_needed(&block->page); + buf_page_make_young_if_needed(&fix_block->page); } #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG ut_a(++buf_dbg_counter % 5771 || buf_validate()); - ut_a(block->page.buf_fix_count > 0); - ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); + ut_a(fix_block->page.buf_fix_count > 0); + ut_a(buf_block_get_state(fix_block) == BUF_BLOCK_FILE_PAGE); #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ +#ifdef PAGE_ATOMIC_REF_COUNT + /* We have to wait here because the IO_READ state was set + under the protection of the hash_lock and the block->mutex + but not the block->lock. */ + buf_wait_for_read(fix_block, trx); +#endif /* PAGE_ATOMIC_REF_COUNT */ + switch (rw_latch) { case RW_NO_LATCH: - if (must_read) { - /* Let us wait until the read operation - completes */ - if (UNIV_UNLIKELY(trx && trx->take_stats)) - { - ut_usectime(&sec, &ms); - start_time = (ib_uint64_t)sec * 1000000 + ms; - } else { - start_time = 0; - } - for (;;) { - enum buf_io_fix io_fix; - - mutex_enter(&block->mutex); - io_fix = buf_block_get_io_fix(block); - mutex_exit(&block->mutex); - - if (io_fix == BUF_IO_READ) { - /* wait by temporaly s-latch */ - rw_lock_s_lock(&(block->lock)); - rw_lock_s_unlock(&(block->lock)); - } else { - break; - } - } - if (UNIV_UNLIKELY(start_time != 0)) - { - ut_usectime(&sec, &ms); - finish_time = (ib_uint64_t)sec * 1000000 + ms; - trx->io_reads_wait_timer += (ulint)(finish_time - start_time); - } - } +#ifndef PAGE_ATOMIC_REF_COUNT + buf_wait_for_read(fix_block, trx); +#endif /* !PAGE_ATOMIC_REF_COUNT */ fix_type = MTR_MEMO_BUF_FIX; break; case RW_S_LATCH: - rw_lock_s_lock_inline(&(block->lock), 0, file, line); + rw_lock_s_lock_inline(&fix_block->lock, 0, file, line); fix_type = MTR_MEMO_PAGE_S_FIX; break; default: ut_ad(rw_latch == RW_X_LATCH); - rw_lock_x_lock_inline(&(block->lock), 0, file, line); + rw_lock_x_lock_inline(&fix_block->lock, 0, file, line); fix_type = MTR_MEMO_PAGE_X_FIX; break; } - mtr_memo_push(mtr, block, fix_type); + mtr_memo_push(mtr, fix_block, fix_type); if (mode != BUF_PEEK_IF_IN_POOL && !access_time) { /* In the case of a first access, try to apply linear read-ahead */ - buf_read_ahead_linear(space, zip_size, offset, - ibuf_inside(mtr), trx); + buf_read_ahead_linear( + space, zip_size, offset, ibuf_inside(mtr), trx); } #ifdef UNIV_IBUF_COUNT_DEBUG - ut_a(ibuf_count_get(buf_block_get_space(block), - buf_block_get_page_no(block)) == 0); + ut_a(ibuf_count_get(buf_block_get_space(fix_block), + buf_block_get_page_no(fix_block)) == 0); #endif #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX)); @@ -3021,7 +3140,7 @@ wait_until_unfixed: _increment_page_get_statistics(block, trx); } - return(block); + return(fix_block); } /********************************************************************//** @@ -3085,9 +3204,7 @@ buf_page_optimistic_get( } if (UNIV_UNLIKELY(!success)) { - mutex_enter(&block->mutex); buf_block_buf_fix_dec(block); - mutex_exit(&block->mutex); return(FALSE); } @@ -3101,9 +3218,7 @@ buf_page_optimistic_get( rw_lock_x_unlock(&(block->lock)); } - mutex_enter(&block->mutex); buf_block_buf_fix_dec(block); - mutex_exit(&block->mutex); return(FALSE); } @@ -3215,9 +3330,7 @@ buf_page_get_known_nowait( } if (!success) { - mutex_enter(&block->mutex); buf_block_buf_fix_dec(block); - mutex_exit(&block->mutex); return(FALSE); } @@ -3325,9 +3438,7 @@ buf_page_try_get_func( } if (!success) { - mutex_enter(&block->mutex); buf_block_buf_fix_dec(block); - mutex_exit(&block->mutex); return(NULL); } @@ -3425,16 +3536,23 @@ buf_page_init( hash_page = buf_page_hash_get_low(buf_pool, space, offset, fold); - if (UNIV_LIKELY(!hash_page)) { + if (hash_page == NULL) { + /* Block not found in the hash table */ } else if (buf_pool_watch_is_sentinel(buf_pool, hash_page)) { - /* Preserve the reference count. */ mutex_enter(&buf_pool->zip_mutex); - ulint buf_fix_count = hash_page->buf_fix_count; + ib_uint32_t buf_fix_count = hash_page->buf_fix_count; ut_a(buf_fix_count > 0); - block->page.buf_fix_count += buf_fix_count; + +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_increment_uint32( + &block->page.buf_fix_count, buf_fix_count); +#else + block->page.buf_fix_count += ulint(buf_fix_count); +#endif /* PAGE_ATOMIC_REF_COUNT */ + buf_pool_watch_remove(buf_pool, fold, hash_page); mutex_exit(&buf_pool->zip_mutex); @@ -3459,8 +3577,9 @@ buf_page_init( ut_ad(!block->page.in_zip_hash); ut_ad(!block->page.in_page_hash); ut_d(block->page.in_page_hash = TRUE); - HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, - fold, &block->page); + + HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold, &block->page); + if (zip_size) { page_zip_set_size(&block->page.zip, zip_size); } @@ -3497,7 +3616,7 @@ buf_page_init_for_read( prio_rw_lock_t* hash_lock; mtr_t mtr; ulint fold; - ibool lru = FALSE; + ibool lru; void* data; buf_pool_t* buf_pool = buf_pool_get(space, offset); @@ -3572,12 +3691,18 @@ err_exit: ut_ad(buf_pool_from_bpage(bpage) == buf_pool); buf_page_init(buf_pool, space, offset, fold, zip_size, block); - rw_lock_x_unlock(hash_lock); + +#ifdef PAGE_ATOMIC_REF_COUNT + /* Note: We set the io state without the protection of + the block->lock. This is because other threads cannot + access this block unless it is in the hash table. */ + + buf_page_set_io_fix(bpage, BUF_IO_READ); +#endif /* PAGE_ATOMIC_REF_COUNT */ /* The block must be put to the LRU list, to the old blocks */ buf_LRU_add_block(bpage, TRUE/* to old blocks */); mutex_exit(&buf_pool->LRU_list_mutex); - lru = TRUE; /* We set a pass-type x-lock on the frame because then the same thread which called for the read operation @@ -3589,7 +3714,12 @@ err_exit: io-handler thread. */ rw_lock_x_lock_gen(&block->lock, BUF_IO_READ); + +#ifndef PAGE_ATOMIC_REF_COUNT buf_page_set_io_fix(bpage, BUF_IO_READ); +#endif /* !PAGE_ATOMIC_REF_COUNT */ + + rw_lock_x_unlock(hash_lock); if (zip_size) { /* buf_pool->LRU_list_mutex may be released and @@ -3628,28 +3758,24 @@ err_exit: rw_lock_x_lock(hash_lock); - /* If buf_buddy_alloc() allocated storage from the LRU list, - it released and reacquired buf_pool->LRU_list_mutex. Thus, we - must check the page_hash again, as it may have been + /* We must check the page_hash again, as it may have been modified. */ - if (UNIV_UNLIKELY(lru)) { - watch_page = buf_page_hash_get_low( + watch_page = buf_page_hash_get_low( buf_pool, space, offset, fold); - if (UNIV_UNLIKELY(watch_page + if (UNIV_UNLIKELY(watch_page && !buf_pool_watch_is_sentinel(buf_pool, watch_page))) { - /* The block was added by some other thread. */ - mutex_exit(&buf_pool->LRU_list_mutex); - rw_lock_x_unlock(hash_lock); - watch_page = NULL; - buf_buddy_free(buf_pool, data, zip_size); + /* The block was added by some other thread. */ + mutex_exit(&buf_pool->LRU_list_mutex); + rw_lock_x_unlock(hash_lock); + watch_page = NULL; + buf_buddy_free(buf_pool, data, zip_size); - bpage = NULL; - goto func_exit; - } + bpage = NULL; + goto func_exit; } bpage = buf_page_alloc_descriptor(); @@ -3681,13 +3807,24 @@ err_exit: ut_d(bpage->in_page_hash = TRUE); - if (UNIV_LIKELY_NULL(watch_page)) { + if (watch_page != NULL) { /* Preserve the reference count. */ - ulint buf_fix_count = watch_page->buf_fix_count; + ib_uint32_t buf_fix_count; + + buf_fix_count = watch_page->buf_fix_count; + ut_a(buf_fix_count > 0); + ut_ad(buf_own_zip_mutex_for_page(bpage)); + +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_increment_uint32( + &bpage->buf_fix_count, buf_fix_count); +#else bpage->buf_fix_count += buf_fix_count; +#endif /* PAGE_ATOMIC_REF_COUNT */ + ut_ad(buf_pool_watch_is_sentinel(buf_pool, watch_page)); buf_pool_watch_remove(buf_pool, fold, watch_page); } @@ -3783,8 +3920,7 @@ buf_page_create( buf_block_free(free_block); - return(buf_page_get_with_no_latch(space, zip_size, - offset, mtr)); + return(buf_page_get_with_no_latch(space, zip_size, offset, mtr)); } /* If we get here, the page was not in buf_pool: init it there */ diff --git a/storage/xtradb/buf/buf0dblwr.cc b/storage/xtradb/buf/buf0dblwr.cc index 506a5b177ba..c1bc0ee4c6e 100644 --- a/storage/xtradb/buf/buf0dblwr.cc +++ b/storage/xtradb/buf/buf0dblwr.cc @@ -351,13 +351,12 @@ At a database startup initializes the doublewrite buffer memory structure if we already have a doublewrite buffer created in the data files. If we are upgrading to an InnoDB version which supports multiple tablespaces, then this function performs the necessary update operations. If we are in a crash -recovery, this function uses a possible doublewrite buffer to restore -half-written pages in the data files. */ +recovery, this function loads the pages from double write buffer into memory. */ UNIV_INTERN void -buf_dblwr_init_or_restore_pages( -/*============================*/ - ibool restore_corrupt_pages) /*!< in: TRUE=restore pages */ +buf_dblwr_init_or_load_pages( +/*==========================*/ + bool load_corrupt_pages) { byte* buf; byte* read_buf; @@ -368,8 +367,8 @@ buf_dblwr_init_or_restore_pages( ibool reset_space_ids = FALSE; byte* doublewrite; ulint space_id; - ulint page_no; ulint i; + recv_dblwr_t& recv_dblwr = recv_sys->dblwr; /* We do the file i/o past the buffer pool */ @@ -431,13 +430,12 @@ buf_dblwr_init_or_restore_pages( for (i = 0; i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * 2; i++) { ulint source_page_no; - page_no = mach_read_from_4(page + FIL_PAGE_OFFSET); if (reset_space_ids) { space_id = 0; mach_write_to_4(page - + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0); + + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id); /* We do not need to calculate new checksums for the pages because the field .._SPACE_ID does not affect them. Write the page back to where we read it from. */ @@ -449,19 +447,50 @@ buf_dblwr_init_or_restore_pages( + i - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE; } - fil_io(OS_FILE_WRITE, true, 0, 0, source_page_no, 0, + fil_io(OS_FILE_WRITE, true, space_id, 0, source_page_no, 0, UNIV_PAGE_SIZE, page, NULL); - } else { - space_id = mach_read_from_4( - page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + } else if (load_corrupt_pages) { + + recv_dblwr.add(page); } - if (!restore_corrupt_pages) { - /* The database was shut down gracefully: no need to - restore pages */ + page += UNIV_PAGE_SIZE; + } - } else if (!fil_tablespace_exists_in_mem(space_id)) { + fil_flush_file_spaces(FIL_TABLESPACE); + +leave_func: + ut_free(unaligned_read_buf); +} + +/****************************************************************//** +Process the double write buffer pages. */ +void +buf_dblwr_process() +/*===============*/ +{ + ulint space_id; + ulint page_no; + ulint page_no_dblwr = 0; + byte* page; + byte* read_buf; + byte* unaligned_read_buf; + recv_dblwr_t& recv_dblwr = recv_sys->dblwr; + + unaligned_read_buf = static_cast(ut_malloc(2 * UNIV_PAGE_SIZE)); + + read_buf = static_cast( + ut_align(unaligned_read_buf, UNIV_PAGE_SIZE)); + + for (std::list::iterator i = recv_dblwr.pages.begin(); + i != recv_dblwr.pages.end(); ++i, ++page_no_dblwr ) { + + page = *i; + page_no = mach_read_from_4(page + FIL_PAGE_OFFSET); + space_id = mach_read_from_4(page + FIL_PAGE_SPACE_ID); + + if (!fil_tablespace_exists_in_mem(space_id)) { /* Maybe we have dropped the single-table tablespace and this page once belonged to it: do nothing */ @@ -472,19 +501,8 @@ buf_dblwr_init_or_restore_pages( "within space bounds; space id %lu " "page number %lu, page %lu in " "doublewrite buf.", - (ulong) space_id, (ulong) page_no, (ulong) i); - - } else if (space_id == TRX_SYS_SPACE - && ((page_no >= block1 - && page_no - < block1 + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) - || (page_no >= block2 - && page_no - < (block2 - + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)))) { - - /* It is an unwritten doublewrite buffer page: - do nothing */ + (ulong) space_id, (ulong) page_no, + page_no_dblwr); } else { ulint zip_size = fil_space_get_zip_size(space_id); @@ -551,14 +569,11 @@ buf_dblwr_init_or_restore_pages( " the doublewrite buffer."); } } - - page += UNIV_PAGE_SIZE; } fil_flush_file_spaces(FIL_TABLESPACE); - -leave_func: ut_free(unaligned_read_buf); + recv_dblwr.pages.clear(); } /****************************************************************//** @@ -776,6 +791,7 @@ buf_dblwr_write_block_to_datafile( fil_io(flags, sync, buf_block_get_space(block), 0, buf_block_get_page_no(block), 0, UNIV_PAGE_SIZE, (void*) block->frame, (void*) block); + } /********************************************************************//** diff --git a/storage/xtradb/buf/buf0flu.cc b/storage/xtradb/buf/buf0flu.cc index a7f55eb9c79..9e92cf321a7 100644 --- a/storage/xtradb/buf/buf0flu.cc +++ b/storage/xtradb/buf/buf0flu.cc @@ -59,8 +59,12 @@ need to protect it by a mutex. It is only ever read by the thread doing the shutdown */ UNIV_INTERN ibool buf_page_cleaner_is_active = FALSE; +/** Flag indicating if the lru_manager is in active state. */ +UNIV_INTERN bool buf_lru_manager_is_active = false; + #ifdef UNIV_PFS_THREAD UNIV_INTERN mysql_pfs_key_t buf_page_cleaner_thread_key; +UNIV_INTERN mysql_pfs_key_t buf_lru_manager_thread_key; #endif /* UNIV_PFS_THREAD */ /** If LRU list of a buf_pool is less than this size then LRU eviction @@ -503,15 +507,15 @@ buf_flush_ready_for_replace( #ifdef UNIV_DEBUG buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); ut_ad(mutex_own(&buf_pool->LRU_list_mutex)); -#endif +#endif /* UNIV_DEBUG */ ut_ad(mutex_own(buf_page_get_mutex(bpage))); ut_ad(bpage->in_LRU_list); - if (UNIV_LIKELY(buf_page_in_file(bpage))) { + if (buf_page_in_file(bpage)) { return(bpage->oldest_modification == 0 - && buf_page_get_io_fix(bpage) == BUF_IO_NONE - && bpage->buf_fix_count == 0); + && bpage->buf_fix_count == 0 + && buf_page_get_io_fix(bpage) == BUF_IO_NONE); } ut_print_timestamp(stderr); @@ -552,13 +556,8 @@ buf_flush_ready_for_flush( case BUF_FLUSH_LIST: case BUF_FLUSH_LRU: case BUF_FLUSH_SINGLE_PAGE: - /* Because any thread may call single page flush, even - when owning locks on pages, to avoid deadlocks, we must - make sure that the that it is not buffer fixed. - The same holds true for LRU flush because a user thread - may end up waiting for an LRU flush to end while - holding locks on other pages. */ - return(bpage->buf_fix_count == 0); + return(true); + case BUF_FLUSH_N_TYPES: break; } @@ -982,9 +981,12 @@ Writes a flushable page asynchronously from the buffer pool to a file. NOTE: in simulated aio we must call os_aio_simulated_wake_handler_threads after we have posted a batch of writes! NOTE: buf_page_get_mutex(bpage) must be held upon entering this -function, and it will be released by this function. */ +function, and it will be released by this function if it returns true. +LRU_list_mutex must be held iff performing a single page flush and will be +released by the function if it returns true. +@return TRUE if the page was flushed */ UNIV_INTERN -void +bool buf_flush_page( /*===========*/ buf_pool_t* buf_pool, /*!< in: buffer pool instance */ @@ -992,111 +994,98 @@ buf_flush_page( buf_flush_t flush_type, /*!< in: type of flush */ bool sync) /*!< in: true if sync IO request */ { - ib_mutex_t* block_mutex; - ibool is_uncompressed; - ut_ad(flush_type < BUF_FLUSH_N_TYPES); - ut_ad(!mutex_own(&buf_pool->LRU_list_mutex)); + /* Hold the LRU list mutex iff called for a single page LRU + flush. A single page LRU flush is already non-performant, and holding + the LRU list mutex allows us to avoid having to store the previous LRU + list page or to restart the LRU scan in + buf_flush_single_page_from_LRU(). */ + ut_ad(flush_type == BUF_FLUSH_SINGLE_PAGE || + !mutex_own(&buf_pool->LRU_list_mutex)); + ut_ad(flush_type != BUF_FLUSH_SINGLE_PAGE || + mutex_own(&buf_pool->LRU_list_mutex)); ut_ad(buf_page_in_file(bpage)); ut_ad(!sync || flush_type == BUF_FLUSH_SINGLE_PAGE); - block_mutex = buf_page_get_mutex(bpage); + ib_mutex_t* block_mutex = buf_page_get_mutex(bpage); + ut_ad(mutex_own(block_mutex)); ut_ad(buf_flush_ready_for_flush(bpage, flush_type)); - mutex_enter(&buf_pool->flush_state_mutex); + bool is_uncompressed; - buf_page_set_io_fix(bpage, BUF_IO_WRITE); + is_uncompressed = (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE); + ut_ad(is_uncompressed == (block_mutex != &buf_pool->zip_mutex)); - buf_page_set_flush_type(bpage, flush_type); + ibool flush; + rw_lock_t* rw_lock; + bool no_fix_count = bpage->buf_fix_count == 0; - if (buf_pool->n_flush[flush_type] == 0) { + if (!is_uncompressed) { + flush = TRUE; + rw_lock = NULL; - os_event_reset(buf_pool->no_flush[flush_type]); + } else if (!(no_fix_count || flush_type == BUF_FLUSH_LIST)) { + /* This is a heuristic, to avoid expensive S attempts. */ + flush = FALSE; + } else { + + rw_lock = &reinterpret_cast(bpage)->lock; + + if (flush_type != BUF_FLUSH_LIST) { + flush = rw_lock_s_lock_gen_nowait( + rw_lock, BUF_IO_WRITE); + } else { + /* Will S lock later */ + flush = TRUE; + } } - buf_pool->n_flush[flush_type]++; + if (flush) { - mutex_exit(&buf_pool->flush_state_mutex); + /* We are committed to flushing by the time we get here */ - is_uncompressed = (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE); - ut_ad(is_uncompressed == (block_mutex != &buf_pool->zip_mutex)); + mutex_enter(&buf_pool->flush_state_mutex); - switch (flush_type) { - ibool is_s_latched; - case BUF_FLUSH_LIST: - /* If the simulated aio thread is not running, we must - not wait for any latch, as we may end up in a deadlock: - if buf_fix_count == 0, then we know we need not wait */ + buf_page_set_io_fix(bpage, BUF_IO_WRITE); - is_s_latched = (bpage->buf_fix_count == 0); - if (is_s_latched && is_uncompressed) { - rw_lock_s_lock_gen(&((buf_block_t*) bpage)->lock, - BUF_IO_WRITE); + buf_page_set_flush_type(bpage, flush_type); + + if (buf_pool->n_flush[flush_type] == 0) { + + os_event_reset(buf_pool->no_flush[flush_type]); } + ++buf_pool->n_flush[flush_type]; + + mutex_exit(&buf_pool->flush_state_mutex); + mutex_exit(block_mutex); - /* Even though bpage is not protected by any mutex at - this point, it is safe to access bpage, because it is - io_fixed and oldest_modification != 0. Thus, it - cannot be relocated in the buffer pool or removed from - flush_list or LRU_list. */ + if (flush_type == BUF_FLUSH_SINGLE_PAGE) + mutex_exit(&buf_pool->LRU_list_mutex); - if (!is_s_latched) { + if (flush_type == BUF_FLUSH_LIST + && is_uncompressed + && !rw_lock_s_lock_gen_nowait(rw_lock, BUF_IO_WRITE)) { + /* avoiding deadlock possibility involves doublewrite + buffer, should flush it, because it might hold the + another block->lock. */ buf_dblwr_flush_buffered_writes(); - if (is_uncompressed) { - rw_lock_s_lock_gen(&((buf_block_t*) bpage) - ->lock, BUF_IO_WRITE); - } - } + rw_lock_s_lock_gen(rw_lock, BUF_IO_WRITE); + } - break; + /* Even though bpage is not protected by any mutex at this + point, it is safe to access bpage, because it is io_fixed and + oldest_modification != 0. Thus, it cannot be relocated in the + buffer pool or removed from flush_list or LRU_list. */ - case BUF_FLUSH_LRU: - case BUF_FLUSH_SINGLE_PAGE: - /* VERY IMPORTANT: - Because any thread may call single page flush, even when - owning locks on pages, to avoid deadlocks, we must make - sure that the s-lock is acquired on the page without - waiting: this is accomplished because - buf_flush_ready_for_flush() must hold, and that requires - the page not to be bufferfixed. - The same holds true for LRU flush because a user thread - may end up waiting for an LRU flush to end while - holding locks on other pages. */ + buf_flush_write_block_low(bpage, flush_type, sync); + } - if (is_uncompressed) { - rw_lock_s_lock_gen(&((buf_block_t*) bpage)->lock, - BUF_IO_WRITE); - } - - /* Note that the s-latch is acquired before releasing the - buf_page_get_mutex() mutex: this ensures that the latch is - acquired immediately. */ - - mutex_exit(block_mutex); - break; - - default: - ut_error; - } - - /* Even though bpage is not protected by any mutex at this - point, it is safe to access bpage, because it is io_fixed and - oldest_modification != 0. Thus, it cannot be relocated in the - buffer pool or removed from flush_list or LRU_list. */ - -#ifdef UNIV_DEBUG - if (buf_debug_prints) { - fprintf(stderr, - "Flushing %u space %u page %u\n", - flush_type, bpage->space, bpage->offset); - } -#endif /* UNIV_DEBUG */ - buf_flush_write_block_low(bpage, flush_type, sync); + return(flush); } # if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG @@ -1115,15 +1104,16 @@ buf_flush_page_try( { ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); ut_ad(mutex_own(&block->mutex)); + ut_ad(mutex_own(&buf_pool->LRU_list_mutex)); if (!buf_flush_ready_for_flush(&block->page, BUF_FLUSH_SINGLE_PAGE)) { return(FALSE); } - /* The following call will release the buffer pool and - block mutex. */ - buf_flush_page(buf_pool, &block->page, BUF_FLUSH_SINGLE_PAGE, true); - return(TRUE); + /* The following call will release the LRU list and + block mutex if successful. */ + return(buf_flush_page( + buf_pool, &block->page, BUF_FLUSH_SINGLE_PAGE, true)); } # endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ /***********************************************************//** @@ -1199,7 +1189,6 @@ buf_flush_try_neighbors( ulint i; ulint low; ulint high; - ulint count = 0; buf_pool_t* buf_pool = buf_pool_get(space, offset); ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST); @@ -1257,9 +1246,10 @@ buf_flush_try_neighbors( high = fil_space_get_size(space); } + ulint count = 0; + for (i = low; i < high; i++) { - buf_page_t* bpage; prio_rw_lock_t* hash_lock; ib_mutex_t* block_mutex; @@ -1281,10 +1271,10 @@ buf_flush_try_neighbors( buf_pool = buf_pool_get(space, i); /* We only want to flush pages from this buffer pool. */ - bpage = buf_page_hash_get_s_locked(buf_pool, space, i, - &hash_lock); + buf_page_t* bpage = buf_page_hash_get_s_locked(buf_pool, + space, i, &hash_lock); - if (!bpage) { + if (bpage == NULL) { continue; } @@ -1305,19 +1295,12 @@ buf_flush_try_neighbors( || buf_page_is_old(bpage)) { if (buf_flush_ready_for_flush(bpage, flush_type) - && (i == offset || !bpage->buf_fix_count)) { - /* We only try to flush those - neighbors != offset where the buf fix - count is zero, as we then know that we - probably can latch the page without a - semaphore wait. Semaphore waits are - expensive because we must flush the - doublewrite buffer before we start - waiting. */ + && (i == offset || bpage->buf_fix_count == 0) + && buf_flush_page( + buf_pool, bpage, flush_type, false)) { + + ++count; - buf_flush_page(buf_pool, bpage, flush_type, false); - ut_ad(!mutex_own(block_mutex)); - count++; continue; } } @@ -1358,8 +1341,8 @@ buf_flush_page_and_try_neighbors( ulint* count) /*!< in/out: number of pages flushed */ { + ibool flushed; ib_mutex_t* block_mutex = NULL; - ibool flushed = FALSE; #ifdef UNIV_DEBUG buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); #endif /* UNIV_DEBUG */ @@ -1374,21 +1357,10 @@ buf_flush_page_and_try_neighbors( mutex_enter(block_mutex); } - if (UNIV_UNLIKELY(buf_page_get_state(bpage) - == BUF_BLOCK_REMOVE_HASH)) { - - /* In case we don't hold the LRU list mutex, we may see a page - that is about to be relocated on the flush list. Do not - attempt to flush it. */ - ut_ad(flush_type == BUF_FLUSH_LIST); - return (flushed); - } - - ut_a(buf_page_in_file(bpage)); + ut_a(buf_page_in_file(bpage) + || buf_page_get_state(bpage) == BUF_BLOCK_REMOVE_HASH); if (buf_flush_ready_for_flush(bpage, flush_type)) { - ulint space; - ulint offset; buf_pool_t* buf_pool; buf_pool = buf_pool_from_bpage(bpage); @@ -1399,8 +1371,10 @@ buf_flush_page_and_try_neighbors( /* These fields are protected by the buf_page_get_mutex() mutex. */ - space = buf_page_get_space(bpage); - offset = buf_page_get_page_no(bpage); + /* Read the fields directly in order to avoid asserting on + BUF_BLOCK_REMOVE_HASH pages. */ + ulint space = bpage->space; + ulint offset = bpage->offset; if (flush_type == BUF_FLUSH_LRU) { mutex_exit(block_mutex); @@ -1409,11 +1383,8 @@ buf_flush_page_and_try_neighbors( } /* Try to flush also all the neighbors */ - *count += buf_flush_try_neighbors(space, - offset, - flush_type, - *count, - n_to_flush); + *count += buf_flush_try_neighbors( + space, offset, flush_type, *count, n_to_flush); if (flush_type == BUF_FLUSH_LRU) { mutex_enter(&buf_pool->LRU_list_mutex); @@ -1421,8 +1392,12 @@ buf_flush_page_and_try_neighbors( buf_flush_list_mutex_enter(buf_pool); } flushed = TRUE; + } else if (flush_type == BUF_FLUSH_LRU) { mutex_exit(block_mutex); + flushed = FALSE; + } else { + flushed = FALSE; } ut_ad((flush_type == BUF_FLUSH_LRU @@ -1574,6 +1549,7 @@ buf_flush_LRU_list_batch( of the flushed pages then the scan becomes O(n*n). */ if (evict) { + if (buf_LRU_free_page(bpage, true)) { mutex_exit(block_mutex); @@ -1588,19 +1564,42 @@ buf_flush_LRU_list_batch( } } else if (UNIV_LIKELY(!failed_acquire)) { + ulint space; + ulint offset; + buf_page_t* prev_bpage; + + prev_bpage = UT_LIST_GET_PREV(LRU, bpage); + + /* Save the previous bpage */ + + if (prev_bpage != NULL) { + space = prev_bpage->space; + offset = prev_bpage->offset; + } else { + space = ULINT_UNDEFINED; + offset = ULINT_UNDEFINED; + } + if (buf_flush_page_and_try_neighbors( bpage, BUF_FLUSH_LRU, max, &n->flushed)) { - lru_position = 0; - /* LRU list mutex was released. - Restart the scan. */ - bpage = UT_LIST_GET_LAST(buf_pool->LRU); - } else { + reposition the iterator. Note: the + prev block could have been repositioned + too but that should be rare. */ - bpage = UT_LIST_GET_PREV(LRU, bpage); + if (prev_bpage != NULL) { + + ut_ad(space != ULINT_UNDEFINED); + ut_ad(offset != ULINT_UNDEFINED); + + prev_bpage = buf_page_hash_get( + buf_pool, space, offset); + } } + + bpage = prev_bpage; } free_len = UT_LIST_GET_LEN(buf_pool->free); @@ -1912,7 +1911,7 @@ buf_flush_wait_batch_end( } } else { thd_wait_begin(NULL, THD_WAIT_DISKIO); - os_event_wait(buf_pool->no_flush[type]); + os_event_wait(buf_pool->no_flush[type]); thd_wait_end(NULL); } } @@ -2101,9 +2100,7 @@ buf_flush_single_page_from_LRU( { ulint scanned; buf_page_t* bpage; - ib_mutex_t* block_mutex; - ibool freed; - bool evict_zip; + ibool flushed = FALSE; mutex_enter(&buf_pool->LRU_list_mutex); @@ -2111,18 +2108,30 @@ buf_flush_single_page_from_LRU( bpage != NULL; bpage = UT_LIST_GET_PREV(LRU, bpage), ++scanned) { - block_mutex = buf_page_get_mutex(bpage); + ib_mutex_t* block_mutex = buf_page_get_mutex(bpage); + mutex_enter(block_mutex); - if (buf_flush_ready_for_flush(bpage, - BUF_FLUSH_SINGLE_PAGE)) { - /* buf_flush_page() will release the block - mutex */ - break; + + if (buf_flush_ready_for_flush(bpage, BUF_FLUSH_SINGLE_PAGE)) { + + /* The following call will release the LRU list + and block mutex. */ + + flushed = buf_flush_page(buf_pool, bpage, + BUF_FLUSH_SINGLE_PAGE, true); + + if (flushed) { + /* buf_flush_page() will release the + block mutex */ + break; + } } + mutex_exit(block_mutex); } - mutex_exit(&buf_pool->LRU_list_mutex); + if (!flushed) + mutex_exit(&buf_pool->LRU_list_mutex); MONITOR_INC_VALUE_CUMULATIVE( MONITOR_LRU_SINGLE_FLUSH_SCANNED, @@ -2130,13 +2139,13 @@ buf_flush_single_page_from_LRU( MONITOR_LRU_SINGLE_FLUSH_SCANNED_PER_CALL, scanned); - if (!bpage) { + if (bpage == NULL) { /* Can't find a single flushable page. */ return(FALSE); } - /* The following call will release the buf_page_get_mutex() mutex. */ - buf_flush_page(buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE, true); + + ibool freed = FALSE; /* At this point the page has been written to the disk. As we are not holding LRU list or buf_page_get_mutex() mutex therefore @@ -2151,30 +2160,30 @@ buf_flush_single_page_from_LRU( bpage != NULL; bpage = UT_LIST_GET_PREV(LRU, bpage)) { - ibool ready; + ib_mutex_t* block_mutex = buf_page_get_mutex(bpage); - block_mutex = buf_page_get_mutex(bpage); mutex_enter(block_mutex); - ready = buf_flush_ready_for_replace(bpage); + + ibool ready = buf_flush_ready_for_replace(bpage); + if (ready) { + bool evict_zip; + + evict_zip = !buf_LRU_evict_from_unzip_LRU(buf_pool);; + + freed = buf_LRU_free_page(bpage, evict_zip); + + mutex_exit(block_mutex); + break; } + mutex_exit(block_mutex); } - if (!bpage) { - /* Can't find a single replaceable page. */ - mutex_exit(&buf_pool->LRU_list_mutex); - return(FALSE); - } - - evict_zip = !buf_LRU_evict_from_unzip_LRU(buf_pool);; - - freed = buf_LRU_free_page(bpage, evict_zip); if (!freed) mutex_exit(&buf_pool->LRU_list_mutex); - mutex_exit(block_mutex); return(freed); } @@ -2626,7 +2635,7 @@ page_cleaner_adapt_flush_sleep_time(void) /******************************************************************//** page_cleaner thread tasked with flushing dirty pages from the buffer -pools. As of now we'll have only one instance of this thread. +pool flush lists. As of now we'll have only one instance of this thread. @return a dummy parameter */ extern "C" UNIV_INTERN os_thread_ret_t @@ -2639,7 +2648,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)( ulint next_loop_time = ut_time_ms() + 1000; ulint n_flushed = 0; ulint last_activity = srv_get_activity_count(); - ulint lru_sleep_time = srv_cleaner_max_lru_time; + ulint last_activity_time = ut_time_ms(); ut_ad(!srv_read_only_mode); @@ -2660,8 +2669,8 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)( while (srv_shutdown_state == SRV_SHUTDOWN_NONE) { - ulint flush_sleep_time; ulint page_cleaner_sleep_time; + ibool server_active; srv_current_thread_priority = srv_cleaner_thread_priority; @@ -2674,20 +2683,20 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)( page_cleaner_sleep_if_needed(next_loop_time); } - page_cleaner_adapt_lru_sleep_time(&lru_sleep_time); - - flush_sleep_time = page_cleaner_adapt_flush_sleep_time(); - - page_cleaner_sleep_time = ut_min(lru_sleep_time, - flush_sleep_time); + page_cleaner_sleep_time + = page_cleaner_adapt_flush_sleep_time(); next_loop_time = ut_time_ms() + page_cleaner_sleep_time; - /* Flush pages from end of LRU if required */ - n_flushed = buf_flush_LRU_tail(); + server_active = srv_check_activity(last_activity); + if (server_active + || ut_time_ms() - last_activity_time < 1000) { - if (srv_check_activity(last_activity)) { - last_activity = srv_get_activity_count(); + if (server_active) { + + last_activity = srv_get_activity_count(); + last_activity_time = ut_time_ms(); + } /* Flush pages from flush_list if required */ n_flushed += page_cleaner_flush_pages_if_needed(); @@ -2778,6 +2787,74 @@ thread_exit: OS_THREAD_DUMMY_RETURN; } +/******************************************************************//** +lru_manager thread tasked with performing LRU flushes and evictions to refill +the buffer pool free lists. As of now we'll have only one instance of this +thread. +@return a dummy parameter */ +extern "C" UNIV_INTERN +os_thread_ret_t +DECLARE_THREAD(buf_flush_lru_manager_thread)( +/*==========================================*/ + void* arg __attribute__((unused))) + /*!< in: a dummy parameter required by + os_thread_create */ +{ + ulint next_loop_time = ut_time_ms() + 1000; + ulint lru_sleep_time = srv_cleaner_max_lru_time; + +#ifdef UNIV_PFS_THREAD + pfs_register_thread(buf_lru_manager_thread_key); +#endif /* UNIV_PFS_THREAD */ + + srv_lru_manager_tid = os_thread_get_tid(); + + os_thread_set_priority(srv_lru_manager_tid, + srv_sched_priority_cleaner); + +#ifdef UNIV_DEBUG_THREAD_CREATION + fprintf(stderr, "InnoDB: lru_manager thread running, id %lu\n", + os_thread_pf(os_thread_get_curr_id())); +#endif /* UNIV_DEBUG_THREAD_CREATION */ + + buf_lru_manager_is_active = true; + + /* On server shutdown, the LRU manager thread runs through cleanup + phase to provide free pages for the master and purge threads. */ + while (srv_shutdown_state == SRV_SHUTDOWN_NONE + || srv_shutdown_state == SRV_SHUTDOWN_CLEANUP) { + + ulint n_flushed_lru; + + srv_current_thread_priority = srv_cleaner_thread_priority; + + page_cleaner_sleep_if_needed(next_loop_time); + + page_cleaner_adapt_lru_sleep_time(&lru_sleep_time); + + next_loop_time = ut_time_ms() + lru_sleep_time; + + n_flushed_lru = buf_flush_LRU_tail(); + + if (n_flushed_lru) { + + MONITOR_INC_VALUE_CUMULATIVE( + MONITOR_FLUSH_BACKGROUND_TOTAL_PAGE, + MONITOR_FLUSH_BACKGROUND_COUNT, + MONITOR_FLUSH_BACKGROUND_PAGES, + n_flushed_lru); + } + } + + buf_lru_manager_is_active = false; + + /* We count the number of threads in os_thread_exit(). A created + thread should always use that to exit and not use return() to exit. */ + os_thread_exit(NULL); + + OS_THREAD_DUMMY_RETURN; +} + #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG /** Functor to validate the flush list. */ diff --git a/storage/xtradb/buf/buf0lru.cc b/storage/xtradb/buf/buf0lru.cc index 8a6d042f4c7..d3e0eda0257 100644 --- a/storage/xtradb/buf/buf0lru.cc +++ b/storage/xtradb/buf/buf0lru.cc @@ -503,17 +503,15 @@ buf_flush_or_remove_page( yet; maybe the system is currently reading it in, or flushing the modifications to the file */ return(false); - } - bool processed = false; - buf_flush_list_mutex_exit(buf_pool); /* We don't have to worry about bpage becoming a dangling pointer by a compressed page flush list relocation because buf_page_get_gen() won't be called for pages from this tablespace. */ + bool processed; mutex_enter(block_mutex); @@ -529,6 +527,7 @@ buf_flush_or_remove_page( mutex_exit(block_mutex); *must_restart = TRUE; + processed = false; } else if (!flush) { @@ -538,29 +537,29 @@ buf_flush_or_remove_page( processed = true; - } else if (buf_flush_ready_for_flush(bpage, - BUF_FLUSH_SINGLE_PAGE)) { + } else if (buf_flush_ready_for_flush(bpage, BUF_FLUSH_SINGLE_PAGE)) { - mutex_exit(&buf_pool->LRU_list_mutex); + if (buf_flush_page( + buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE, false)) { - /* The following call will release the buf_page_get_mutex() - mutex. */ - buf_flush_page(buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE, false); - ut_ad(!mutex_own(block_mutex)); + /* Wake possible simulated aio thread to actually + post the writes to the operating system */ + os_aio_simulated_wake_handler_threads(); - /* Wake possible simulated aio thread to actually - post the writes to the operating system */ - os_aio_simulated_wake_handler_threads(); + mutex_enter(&buf_pool->LRU_list_mutex); - mutex_enter(&buf_pool->LRU_list_mutex); + processed = true; + + } else { + mutex_exit(block_mutex); + + processed = false; + } - processed = true; } else { - /* Not ready for flush. It can't be IO fixed because we - checked for that at the start of the function. It must - be buffer fixed. */ - ut_ad(bpage->buf_fix_count > 0); mutex_exit(block_mutex); + + processed = false; } buf_flush_list_mutex_enter(buf_pool); @@ -1365,8 +1364,9 @@ loop: } if (srv_empty_free_list_algorithm == SRV_EMPTY_FREE_LIST_BACKOFF - && buf_page_cleaner_is_active - && srv_shutdown_state == SRV_SHUTDOWN_NONE) { + && buf_lru_manager_is_active + && (srv_shutdown_state == SRV_SHUTDOWN_NONE + || srv_shutdown_state == SRV_SHUTDOWN_CLEANUP)) { /* Backoff to minimize the free list mutex contention while the free list is empty */ @@ -1408,12 +1408,13 @@ loop: goto loop; } else { - /* The cleaner is not running or Oracle MySQL 5.6 algorithm was - requested, will perform a single page flush */ + /* The LRU manager is not running or Oracle MySQL 5.6 algorithm + was requested, will perform a single page flush */ ut_ad((srv_empty_free_list_algorithm == SRV_EMPTY_FREE_LIST_LEGACY) - || !buf_page_cleaner_is_active - || (srv_shutdown_state != SRV_SHUTDOWN_NONE)); + || !buf_lru_manager_is_active + || (srv_shutdown_state != SRV_SHUTDOWN_NONE + && srv_shutdown_state != SRV_SHUTDOWN_CLEANUP)); } mutex_enter(&buf_pool->flush_state_mutex); @@ -1829,8 +1830,6 @@ buf_LRU_add_block_low( { buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); - ut_ad(buf_pool); - ut_ad(bpage); ut_ad(mutex_own(&buf_pool->LRU_list_mutex)); ut_a(buf_page_in_file(bpage)); @@ -1980,7 +1979,7 @@ buf_LRU_free_page( if (!buf_page_can_relocate(bpage)) { - /* Do not free buffer-fixed or I/O-fixed blocks. */ + /* Do not free buffer fixed or I/O-fixed blocks. */ return(false); } @@ -1995,12 +1994,10 @@ buf_LRU_free_page( if (bpage->oldest_modification) { return(false); } - } else if ((bpage->oldest_modification) - && (buf_page_get_state(bpage) - != BUF_BLOCK_FILE_PAGE)) { + } else if (bpage->oldest_modification > 0 + && buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) { - ut_ad(buf_page_get_state(bpage) - == BUF_BLOCK_ZIP_DIRTY); + ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_DIRTY); return(false); @@ -2088,10 +2085,8 @@ not_freed: rw_lock_x_lock(hash_lock); mutex_enter(block_mutex); - ut_a(!buf_page_hash_get_low(buf_pool, - bpage->space, - bpage->offset, - fold)); + ut_a(!buf_page_hash_get_low( + buf_pool, b->space, b->offset, fold)); b->state = b->oldest_modification ? BUF_BLOCK_ZIP_DIRTY @@ -2489,6 +2484,11 @@ buf_LRU_block_remove_hashed( UNIV_PAGE_SIZE); buf_page_set_state(bpage, BUF_BLOCK_REMOVE_HASH); + if (buf_pool->flush_rbt == NULL) { + bpage->space = ULINT32_UNDEFINED; + bpage->offset = ULINT32_UNDEFINED; + } + /* Question: If we release bpage and hash mutex here then what protects us against: 1) Some other thread buffer fixing this page diff --git a/storage/xtradb/dict/dict0boot.cc b/storage/xtradb/dict/dict0boot.cc index 94a3af2852b..b57a8873bd5 100644 --- a/storage/xtradb/dict/dict0boot.cc +++ b/storage/xtradb/dict/dict0boot.cc @@ -302,7 +302,8 @@ dict_boot(void) /* Insert into the dictionary cache the descriptions of the basic system tables */ /*-------------------------*/ - table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, 0, 0); + table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, 0, 0, + false); dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0); @@ -356,7 +357,8 @@ dict_boot(void) ut_a(error == DB_SUCCESS); /*-------------------------*/ - table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, 0, 0); + table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, 0, 0, + false); dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4); @@ -389,7 +391,8 @@ dict_boot(void) ut_a(error == DB_SUCCESS); /*-------------------------*/ - table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, 0, 0); + table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, 0, 0, + false); dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0); @@ -422,7 +425,8 @@ dict_boot(void) ut_a(error == DB_SUCCESS); /*-------------------------*/ - table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, 0, 0); + table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, 0, 0, + false); dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4); diff --git a/storage/xtradb/dict/dict0crea.cc b/storage/xtradb/dict/dict0crea.cc index eba5417dc76..ff892749d4f 100644 --- a/storage/xtradb/dict/dict0crea.cc +++ b/storage/xtradb/dict/dict0crea.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2013, 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 @@ -270,6 +270,12 @@ dict_build_table_def_step( thr_get_trx(thr)->table_id = table->id; + /* Always set this bit for all new created tables */ + DICT_TF2_FLAG_SET(table, DICT_TF2_FTS_AUX_HEX_NAME); + DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name", + DICT_TF2_FLAG_UNSET(table, + DICT_TF2_FTS_AUX_HEX_NAME);); + if (use_tablespace) { /* This table will not use the system tablespace. Get a new space id. */ diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc index 0aaec42cd2f..5cc013b7d6b 100644 --- a/storage/xtradb/dict/dict0dict.cc +++ b/storage/xtradb/dict/dict0dict.cc @@ -121,19 +121,6 @@ UNIV_INTERN mysql_pfs_key_t dict_foreign_err_mutex_key; /** Identifies generated InnoDB foreign key names */ static char dict_ibfk[] = "_ibfk_"; -/** array of rw locks protecting -dict_table_t::stat_initialized -dict_table_t::stat_n_rows (*) -dict_table_t::stat_clustered_index_size -dict_table_t::stat_sum_of_other_index_sizes -dict_table_t::stat_modified_counter (*) -dict_table_t::indexes*::stat_n_diff_key_vals[] -dict_table_t::indexes*::stat_index_size -dict_table_t::indexes*::stat_n_leaf_pages -(*) those are not always protected for performance reasons */ -#define DICT_TABLE_STATS_LATCHES_SIZE 64 -static rw_lock_t dict_table_stats_latches[DICT_TABLE_STATS_LATCHES_SIZE]; - /*******************************************************************//** Tries to find column names for the index and sets the col field of the index. @@ -332,32 +319,31 @@ dict_mutex_exit_for_mysql(void) mutex_exit(&(dict_sys->mutex)); } -/** Get the latch that protects the stats of a given table */ -#define GET_TABLE_STATS_LATCH(table) \ - (&dict_table_stats_latches[ut_fold_ull((ib_uint64_t) table) \ - % DICT_TABLE_STATS_LATCHES_SIZE]) - /**********************************************************************//** -Lock the appropriate latch to protect a given table's statistics. -table->id is used to pick the corresponding latch from a global array of -latches. */ +Lock the appropriate latch to protect a given table's statistics. */ UNIV_INTERN void dict_table_stats_lock( /*==================*/ - const dict_table_t* table, /*!< in: table */ - ulint latch_mode) /*!< in: RW_S_LATCH or - RW_X_LATCH */ + dict_table_t* table, /*!< in: table */ + ulint latch_mode) /*!< in: RW_S_LATCH or RW_X_LATCH */ { ut_ad(table != NULL); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + if (table->stats_latch == NULL) { + /* This is a dummy table object that is private in the current + thread and is not shared between multiple threads, thus we + skip any locking. */ + return; + } + switch (latch_mode) { case RW_S_LATCH: - rw_lock_s_lock(GET_TABLE_STATS_LATCH(table)); + rw_lock_s_lock(table->stats_latch); break; case RW_X_LATCH: - rw_lock_x_lock(GET_TABLE_STATS_LATCH(table)); + rw_lock_x_lock(table->stats_latch); break; case RW_NO_LATCH: /* fall through */ @@ -372,19 +358,26 @@ UNIV_INTERN void dict_table_stats_unlock( /*====================*/ - const dict_table_t* table, /*!< in: table */ - ulint latch_mode) /*!< in: RW_S_LATCH or + dict_table_t* table, /*!< in: table */ + ulint latch_mode) /*!< in: RW_S_LATCH or RW_X_LATCH */ { ut_ad(table != NULL); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + if (table->stats_latch == NULL) { + /* This is a dummy table object that is private in the current + thread and is not shared between multiple threads, thus we + skip any locking. */ + return; + } + switch (latch_mode) { case RW_S_LATCH: - rw_lock_s_unlock(GET_TABLE_STATS_LATCH(table)); + rw_lock_s_unlock(table->stats_latch); break; case RW_X_LATCH: - rw_lock_x_unlock(GET_TABLE_STATS_LATCH(table)); + rw_lock_x_unlock(table->stats_latch); break; case RW_NO_LATCH: /* fall through */ @@ -880,8 +873,6 @@ void dict_init(void) /*===========*/ { - int i; - dict_sys = static_cast(mem_zalloc(sizeof(*dict_sys))); mutex_create(dict_sys_mutex_key, &dict_sys->mutex, SYNC_DICT); @@ -902,11 +893,6 @@ dict_init(void) mutex_create(dict_foreign_err_mutex_key, &dict_foreign_err_mutex, SYNC_NO_ORDER_CHECK); } - - for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) { - rw_lock_create(dict_table_stats_latch_key, - &dict_table_stats_latches[i], SYNC_INDEX_TREE); - } } /**********************************************************************//** @@ -5770,7 +5756,8 @@ dict_ind_init(void) dict_table_t* table; /* create dummy table and index for REDUNDANT infimum and supremum */ - table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0, 0); + table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0, 0, + true); dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR, DATA_ENGLISH | DATA_NOT_NULL, 8); @@ -5783,7 +5770,7 @@ dict_ind_init(void) /* create dummy table and index for COMPACT infimum and supremum */ table = dict_mem_table_create("SYS_DUMMY2", DICT_HDR_SPACE, 1, - DICT_TF_COMPACT, 0); + DICT_TF_COMPACT, 0, true); dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR, DATA_ENGLISH | DATA_NOT_NULL, 8); dict_ind_compact = dict_mem_index_create("SYS_DUMMY2", "SYS_DUMMY2", @@ -6010,6 +5997,17 @@ dict_table_check_for_dup_indexes( } #endif /* UNIV_DEBUG */ +/** Auxiliary macro used inside dict_table_schema_check(). */ +#define CREATE_TYPES_NAMES() \ + dtype_sql_name((unsigned) req_schema->columns[i].mtype, \ + (unsigned) req_schema->columns[i].prtype_mask, \ + (unsigned) req_schema->columns[i].len, \ + req_type, sizeof(req_type)); \ + dtype_sql_name(table->cols[j].mtype, \ + table->cols[j].prtype, \ + table->cols[j].len, \ + actual_type, sizeof(actual_type)) + /*********************************************************************//** Checks whether a table exists and whether it has the given structure. The table must have the same number of columns with the same names and @@ -6029,6 +6027,8 @@ dict_table_schema_check( size_t errstr_sz) /*!< in: errstr size */ { char buf[MAX_FULL_NAME_LEN]; + char req_type[64]; + char actual_type[64]; dict_table_t* table; ulint i; @@ -6080,9 +6080,6 @@ dict_table_schema_check( for (i = 0; i < req_schema->n_cols; i++) { ulint j; - char req_type[64]; - char actual_type[64]; - /* check if i'th column is the same in both arrays */ if (innobase_strcasecmp(req_schema->columns[i].name, dict_table_get_col_name(table, i)) == 0) { @@ -6124,19 +6121,11 @@ dict_table_schema_check( /* we found a column with the same name on j'th position, compare column types and flags */ - dtype_sql_name(req_schema->columns[i].mtype, - req_schema->columns[i].prtype_mask, - req_schema->columns[i].len, - req_type, sizeof(req_type)); - - dtype_sql_name(table->cols[j].mtype, - table->cols[j].prtype, - table->cols[j].len, - actual_type, sizeof(actual_type)); - /* check length for exact match */ if (req_schema->columns[i].len != table->cols[j].len) { + CREATE_TYPES_NAMES(); + ut_snprintf(errstr, errstr_sz, "Column %s in table %s is %s " "but should be %s (length mismatch).", @@ -6151,6 +6140,8 @@ dict_table_schema_check( /* check mtype for exact match */ if (req_schema->columns[i].mtype != table->cols[j].mtype) { + CREATE_TYPES_NAMES(); + ut_snprintf(errstr, errstr_sz, "Column %s in table %s is %s " "but should be %s (type mismatch).", @@ -6168,6 +6159,8 @@ dict_table_schema_check( & req_schema->columns[i].prtype_mask) != req_schema->columns[i].prtype_mask) { + CREATE_TYPES_NAMES(); + ut_snprintf(errstr, errstr_sz, "Column %s in table %s is %s " "but should be %s (flags mismatch).", @@ -6326,10 +6319,6 @@ dict_close(void) mem_free(dict_sys); dict_sys = NULL; - - for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) { - rw_lock_free(&dict_table_stats_latches[i]); - } } #ifdef UNIV_DEBUG diff --git a/storage/xtradb/dict/dict0load.cc b/storage/xtradb/dict/dict0load.cc index 5c97b5aba7c..9add88c0ea5 100644 --- a/storage/xtradb/dict/dict0load.cc +++ b/storage/xtradb/dict/dict0load.cc @@ -1092,10 +1092,34 @@ loop: case DICT_CHECK_ALL_LOADED: /* All tablespaces should have been found in fil_load_single_table_tablespaces(). */ - - fil_space_for_table_exists_in_mem( + if (fil_space_for_table_exists_in_mem( space_id, name, TRUE, !(is_temp || discarded), - false, NULL, 0); + false, NULL, 0) + && !(is_temp || discarded)) { + /* If user changes the path of .ibd files in + *.isl files before doing crash recovery , + then this leads to inconsistency in + SYS_DATAFILES system table because the + tables are loaded from the updated path + but the SYS_DATAFILES still points to the + old path.Therefore after crash recovery + update SYS_DATAFILES with the updated path.*/ + ut_ad(space_id); + ut_ad(recv_needed_recovery); + char *dict_path = dict_get_first_path(space_id, + name); + char *remote_path = fil_read_link_file(name); + if(dict_path && remote_path) { + if(strcmp(dict_path,remote_path)) { + dict_update_filepath(space_id, + remote_path); + } + } + if(dict_path) + mem_free(dict_path); + if(remote_path) + mem_free(remote_path); + } break; case DICT_CHECK_SOME_LOADED: @@ -2151,7 +2175,8 @@ err_len: /* See if the tablespace is available. */ *table = dict_mem_table_create( - name, space, n_cols & ~DICT_N_COLS_COMPACT, flags, flags2); + name, space, n_cols & ~DICT_N_COLS_COMPACT, flags, flags2, + false); field = rec_get_nth_field_old(rec, DICT_FLD__SYS_TABLES__ID, &len); ut_ad(len == 8); /* this was checked earlier */ diff --git a/storage/xtradb/dict/dict0mem.cc b/storage/xtradb/dict/dict0mem.cc index f69e6cc47ae..7ce42fa8efc 100644 --- a/storage/xtradb/dict/dict0mem.cc +++ b/storage/xtradb/dict/dict0mem.cc @@ -65,7 +65,10 @@ dict_mem_table_create( the table is placed */ ulint n_cols, /*!< in: number of columns */ ulint flags, /*!< in: table flags */ - ulint flags2) /*!< in: table flags2 */ + ulint flags2, /*!< in: table flags2 */ + bool nonshared)/*!< in: whether the table object is a dummy + one that does not need the initialization of + locking-related fields. */ { dict_table_t* table; mem_heap_t* heap; @@ -95,12 +98,27 @@ dict_mem_table_create( ut_d(table->magic_n = DICT_TABLE_MAGIC_N); -#ifndef UNIV_HOTBACKUP - table->autoinc_lock = static_cast( - mem_heap_alloc(heap, lock_get_size())); + if (!nonshared) { + table->stats_latch = new rw_lock_t; + rw_lock_create(dict_table_stats_latch_key, table->stats_latch, + SYNC_INDEX_TREE); + } else { + table->stats_latch = NULL; + } - mutex_create(autoinc_mutex_key, - &table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX); +#ifndef UNIV_HOTBACKUP + + if (!nonshared) { + + table->autoinc_lock = static_cast( + mem_heap_alloc(heap, lock_get_size())); + + mutex_create(autoinc_mutex_key, + &table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX); + } else { + + table->autoinc_lock = NULL; + } table->autoinc = 0; @@ -150,8 +168,18 @@ dict_mem_table_free( } } #ifndef UNIV_HOTBACKUP - mutex_free(&(table->autoinc_mutex)); + if (table->stats_latch) { + + mutex_free(&(table->autoinc_mutex)); + } #endif /* UNIV_HOTBACKUP */ + + if (table->stats_latch) { + + rw_lock_free(table->stats_latch); + delete table->stats_latch; + } + ut_free(table->name); mem_heap_free(table->heap); } diff --git a/storage/xtradb/dict/dict0stats.cc b/storage/xtradb/dict/dict0stats.cc index 8bf02f9785c..68c02a301cd 100644 --- a/storage/xtradb/dict/dict0stats.cc +++ b/storage/xtradb/dict/dict0stats.cc @@ -400,6 +400,11 @@ dict_stats_table_clone_create( t->corrupted = table->corrupted; + /* This private object "t" is not shared with other threads, so + we do not need the stats_latch. The lock/unlock routines will do + nothing if stats_latch is NULL. */ + t->stats_latch = NULL; + UT_LIST_INIT(t->indexes); for (index = dict_table_get_first_index(table); @@ -731,7 +736,7 @@ static dict_table_t* dict_stats_snapshot_create( /*=======================*/ - const dict_table_t* table) /*!< in: table whose stats to copy */ + dict_table_t* table) /*!< in: table whose stats to copy */ { mutex_enter(&dict_sys->mutex); @@ -2131,8 +2136,16 @@ dict_stats_save_index_stat( ret = dict_stats_exec_sql( pinfo, - "PROCEDURE INDEX_STATS_SAVE_INSERT () IS\n" + "PROCEDURE INDEX_STATS_SAVE () IS\n" "BEGIN\n" + + "DELETE FROM \"" INDEX_STATS_NAME "\"\n" + "WHERE\n" + "database_name = :database_name AND\n" + "table_name = :table_name AND\n" + "index_name = :index_name AND\n" + "stat_name = :stat_name;\n" + "INSERT INTO \"" INDEX_STATS_NAME "\"\n" "VALUES\n" "(\n" @@ -2147,47 +2160,6 @@ dict_stats_save_index_stat( ");\n" "END;"); - if (ret == DB_DUPLICATE_KEY) { - - pinfo = pars_info_create(); - pars_info_add_str_literal(pinfo, "database_name", db_utf8); - pars_info_add_str_literal(pinfo, "table_name", table_utf8); - UNIV_MEM_ASSERT_RW_ABORT(index->name, strlen(index->name)); - pars_info_add_str_literal(pinfo, "index_name", index->name); - UNIV_MEM_ASSERT_RW_ABORT(&last_update, 4); - pars_info_add_int4_literal(pinfo, "last_update", last_update); - UNIV_MEM_ASSERT_RW_ABORT(stat_name, strlen(stat_name)); - pars_info_add_str_literal(pinfo, "stat_name", stat_name); - UNIV_MEM_ASSERT_RW_ABORT(&stat_value, 8); - pars_info_add_ull_literal(pinfo, "stat_value", stat_value); - if (sample_size != NULL) { - UNIV_MEM_ASSERT_RW_ABORT(sample_size, 8); - pars_info_add_ull_literal(pinfo, "sample_size", *sample_size); - } else { - pars_info_add_literal(pinfo, "sample_size", NULL, - UNIV_SQL_NULL, DATA_FIXBINARY, 0); - } - UNIV_MEM_ASSERT_RW_ABORT(stat_description, strlen(stat_description)); - pars_info_add_str_literal(pinfo, "stat_description", - stat_description); - - ret = dict_stats_exec_sql( - pinfo, - "PROCEDURE INDEX_STATS_SAVE_UPDATE () IS\n" - "BEGIN\n" - "UPDATE \"" INDEX_STATS_NAME "\" SET\n" - "last_update = :last_update,\n" - "stat_value = :stat_value,\n" - "sample_size = :sample_size,\n" - "stat_description = :stat_description\n" - "WHERE\n" - "database_name = :database_name AND\n" - "table_name = :table_name AND\n" - "index_name = :index_name AND\n" - "stat_name = :stat_name;\n" - "END;"); - } - if (ret != DB_SUCCESS) { char buf_table[MAX_FULL_NAME_LEN]; char buf_index[MAX_FULL_NAME_LEN]; @@ -2205,14 +2177,18 @@ dict_stats_save_index_stat( return(ret); } -/*********************************************************************//** -Save the table's statistics into the persistent statistics storage. +/** Save the table's statistics into the persistent statistics storage. +@param[in] table_orig table whose stats to save +@param[in] only_for_index if this is non-NULL, then stats for indexes +that are not equal to it will not be saved, if NULL, then all +indexes' stats are saved @return DB_SUCCESS or error code */ static dberr_t dict_stats_save( /*============*/ - dict_table_t* table_orig) /*!< in: table */ + dict_table_t* table_orig, + const index_id_t* only_for_index) { pars_info_t* pinfo; lint now; @@ -2234,26 +2210,27 @@ dict_stats_save( lint */ now = (lint) ut_time(); -#define PREPARE_PINFO_FOR_TABLE_SAVE(p, t, n) \ - do { \ - pars_info_add_str_literal((p), "database_name", db_utf8); \ - pars_info_add_str_literal((p), "table_name", table_utf8); \ - pars_info_add_int4_literal((p), "last_update", (n)); \ - pars_info_add_ull_literal((p), "n_rows", (t)->stat_n_rows); \ - pars_info_add_ull_literal((p), "clustered_index_size", \ - (t)->stat_clustered_index_size); \ - pars_info_add_ull_literal((p), "sum_of_other_index_sizes", \ - (t)->stat_sum_of_other_index_sizes); \ - } while(false); - pinfo = pars_info_create(); - PREPARE_PINFO_FOR_TABLE_SAVE(pinfo, table, now); + pars_info_add_str_literal(pinfo, "database_name", db_utf8); + pars_info_add_str_literal(pinfo, "table_name", table_utf8); + pars_info_add_int4_literal(pinfo, "last_update", now); + pars_info_add_ull_literal(pinfo, "n_rows", table->stat_n_rows); + pars_info_add_ull_literal(pinfo, "clustered_index_size", + table->stat_clustered_index_size); + pars_info_add_ull_literal(pinfo, "sum_of_other_index_sizes", + table->stat_sum_of_other_index_sizes); ret = dict_stats_exec_sql( pinfo, - "PROCEDURE TABLE_STATS_SAVE_INSERT () IS\n" + "PROCEDURE TABLE_STATS_SAVE () IS\n" "BEGIN\n" + + "DELETE FROM \"" TABLE_STATS_NAME "\"\n" + "WHERE\n" + "database_name = :database_name AND\n" + "table_name = :table_name;\n" + "INSERT INTO \"" TABLE_STATS_NAME "\"\n" "VALUES\n" "(\n" @@ -2266,27 +2243,6 @@ dict_stats_save( ");\n" "END;"); - if (ret == DB_DUPLICATE_KEY) { - pinfo = pars_info_create(); - - PREPARE_PINFO_FOR_TABLE_SAVE(pinfo, table, now); - - ret = dict_stats_exec_sql( - pinfo, - "PROCEDURE TABLE_STATS_SAVE_UPDATE () IS\n" - "BEGIN\n" - "UPDATE \"" TABLE_STATS_NAME "\" SET\n" - "last_update = :last_update,\n" - "n_rows = :n_rows,\n" - "clustered_index_size = :clustered_index_size,\n" - "sum_of_other_index_sizes = " - " :sum_of_other_index_sizes\n" - "WHERE\n" - "database_name = :database_name AND\n" - "table_name = :table_name;\n" - "END;"); - } - if (ret != DB_SUCCESS) { char buf[MAX_FULL_NAME_LEN]; ut_print_timestamp(stderr); @@ -2304,6 +2260,10 @@ dict_stats_save( index != NULL; index = dict_table_get_next_index(index)) { + if (only_for_index != NULL && index->id != *only_for_index) { + continue; + } + if (dict_stats_should_ignore_index(index)) { continue; } @@ -2860,7 +2820,7 @@ dict_stats_update_for_index( dict_table_stats_lock(index->table, RW_X_LATCH); dict_stats_analyze_index(index); dict_table_stats_unlock(index->table, RW_X_LATCH); - dict_stats_save(index->table); + dict_stats_save(index->table, &index->id); DBUG_VOID_RETURN; } /* else */ @@ -2955,7 +2915,7 @@ dict_stats_update( return(err); } - err = dict_stats_save(table); + err = dict_stats_save(table, NULL); return(err); } @@ -2988,7 +2948,7 @@ dict_stats_update( if (dict_stats_persistent_storage_check(false)) { - return(dict_stats_save(table)); + return(dict_stats_save(table, NULL)); } return(DB_STATS_DO_NOT_EXIST); @@ -3834,7 +3794,7 @@ test_dict_stats_save() index2_stat_n_sample_sizes[2] = TEST_IDX2_N_DIFF3_SAMPLE_SIZE; index2_stat_n_sample_sizes[3] = TEST_IDX2_N_DIFF4_SAMPLE_SIZE; - ret = dict_stats_save(&table); + ret = dict_stats_save(&table, NULL); ut_a(ret == DB_SUCCESS); diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index 5e797f2583c..ee3c3943ab8 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -2409,27 +2409,21 @@ fil_op_log_parse_or_replay( break; case MLOG_FILE_RENAME: - /* We do the rename based on space id, not old file name; - this should guarantee that after the log replay each .ibd file - has the correct name for the latest log sequence number; the - proof is left as an exercise :) */ + /* In order to replay the rename, the following must hold: + * The new name is not already used. + * A tablespace is open in memory with the old name. + * The space ID for that tablepace matches this log entry. + This will prevent unintended renames during recovery. */ - if (fil_tablespace_exists_in_mem(space_id)) { + if (fil_get_space_id_for_table(new_name) == ULINT_UNDEFINED + && space_id == fil_get_space_id_for_table(name)) { /* Create the database directory for the new name, if it does not exist yet */ fil_create_directory_for_tablename(new_name); - /* Rename the table if there is not yet a tablespace - with the same name */ - - if (fil_get_space_id_for_table(new_name) - == ULINT_UNDEFINED) { - /* We do not care about the old name, that - is why we pass NULL as the first argument. */ - if (!fil_rename_tablespace(NULL, space_id, - new_name, NULL)) { - ut_error; - } + if (!fil_rename_tablespace(name, space_id, + new_name, NULL)) { + ut_error; } } @@ -4035,6 +4029,176 @@ fil_make_ibbackup_old_name( } #endif /* UNIV_HOTBACKUP */ + +/*******************************************************************//** +Determine the space id of the given file descriptor by reading a few +pages from the beginning of the .ibd file. +@return true if space id was successfully identified, or false. */ +static +bool +fil_user_tablespace_find_space_id( +/*==============================*/ + fsp_open_info* fsp) /* in/out: contains file descriptor, which is + used as input. contains space_id, which is + the output */ +{ + bool st; + os_offset_t file_size; + + file_size = os_file_get_size(fsp->file); + + if (file_size == (os_offset_t) -1) { + ib_logf(IB_LOG_LEVEL_ERROR, "Could not get file size: %s", + fsp->filepath); + return(false); + } + + /* Assuming a page size, read the space_id from each page and store it + in a map. Find out which space_id is agreed on by majority of the + pages. Choose that space_id. */ + for (ulint page_size = UNIV_ZIP_SIZE_MIN; + page_size <= UNIV_PAGE_SIZE_MAX; page_size <<= 1) { + + /* map[space_id] = count of pages */ + std::map verify; + + ulint page_count = 64; + ulint valid_pages = 0; + + /* Adjust the number of pages to analyze based on file size */ + while ((page_count * page_size) > file_size) { + --page_count; + } + + ib_logf(IB_LOG_LEVEL_INFO, "Page size:%lu Pages to analyze:" + "%lu", page_size, page_count); + + byte* buf = static_cast(ut_malloc(2*page_size)); + byte* page = static_cast(ut_align(buf, page_size)); + + for (ulint j = 0; j < page_count; ++j) { + + st = os_file_read(fsp->file, page, (j* page_size), page_size); + + if (!st) { + ib_logf(IB_LOG_LEVEL_INFO, + "READ FAIL: page_no:%lu", j); + continue; + } + + bool uncompressed_ok = false; + + /* For uncompressed pages, the page size must be equal + to UNIV_PAGE_SIZE. */ + if (page_size == UNIV_PAGE_SIZE) { + uncompressed_ok = !buf_page_is_corrupted( + false, page, 0); + } + + bool compressed_ok = !buf_page_is_corrupted( + false, page, page_size); + + if (uncompressed_ok || compressed_ok) { + + ulint space_id = mach_read_from_4(page + + FIL_PAGE_SPACE_ID); + + if (space_id > 0) { + ib_logf(IB_LOG_LEVEL_INFO, + "VALID: space:%lu " + "page_no:%lu page_size:%lu", + space_id, j, page_size); + verify[space_id]++; + ++valid_pages; + } + } + } + + ut_free(buf); + + ib_logf(IB_LOG_LEVEL_INFO, "Page size: %lu, Possible space_id " + "count:" UINT64PF, page_size, + static_cast(verify.size())); + + const ulint pages_corrupted = 3; + for (ulint missed = 0; missed <= pages_corrupted; ++missed) { + + for (std::map::iterator + m = verify.begin(); m != verify.end(); ++m ) { + + ib_logf(IB_LOG_LEVEL_INFO, "space_id:%lu, " + "Number of pages matched: %lu/%lu " + "(%lu)", m->first, m->second, + valid_pages, page_size); + + if (m->second == (valid_pages - missed)) { + + ib_logf(IB_LOG_LEVEL_INFO, + "Chosen space:%lu\n", m->first); + + fsp->id = m->first; + return(true); + } + } + + } + } + + return(false); +} + +/*******************************************************************//** +Finds the page 0 of the given space id from the double write buffer, and +copies it to the corresponding .ibd file. +@return true if copy was successful, or false. */ +static +bool +fil_user_tablespace_restore_page0( +/*==============================*/ + fsp_open_info* fsp) /* in: contains space id and .ibd file + information */ +{ + bool err; + ulint flags; + ulint zip_size; + ulint page_no; + ulint page_size; + ulint buflen; + byte* page; + + ib_logf(IB_LOG_LEVEL_INFO, "Restoring first page of tablespace %lu", + fsp->id); + + if (fsp->id == 0) { + err = false; + goto out; + } + + // find if double write buffer has page0 of given space id + page = recv_sys->dblwr.find_first_page(fsp->id); + + if (!page) { + err = false; + goto out; + } + + flags = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page); + zip_size = fsp_flags_get_zip_size(flags); + page_no = page_get_page_no(page); + page_size = fsp_flags_get_page_size(flags); + + ut_ad(page_no == 0); + + buflen = zip_size ? zip_size: page_size; + + ib_logf(IB_LOG_LEVEL_INFO, "Writing %lu bytes into file: %s", + buflen, fsp->filepath); + + err = os_file_write(fsp->filepath, fsp->file, page, 0, buflen); +out: + return(err); +} + /********************************************************************//** Opens an .ibd file and adds the associated single-table tablespace to the InnoDB fil0fil.cc data structures. @@ -4046,6 +4210,10 @@ fil_validate_single_table_tablespace( const char* tablename, /*!< in: database/tablename */ fsp_open_info* fsp) /*!< in/out: tablespace info */ { + bool restore_attempted = false; + +check_first_page: + fsp->success = TRUE; if (const char* check_msg = fil_read_first_page( fsp->file, FALSE, &fsp->flags, &fsp->id, &fsp->lsn, &fsp->lsn)) { @@ -4053,6 +4221,19 @@ fil_validate_single_table_tablespace( "%s in tablespace %s (table %s)", check_msg, fsp->filepath, tablename); fsp->success = FALSE; + } + + if (!fsp->success) { + if (!restore_attempted) { + if (!fil_user_tablespace_find_space_id(fsp)) { + return; + } + restore_attempted = true; + if (!fil_user_tablespace_restore_page0(fsp)) { + return; + } + goto check_first_page; + } return; } @@ -4170,7 +4351,7 @@ fil_load_single_table_tablespace( /* Try to open the tablespace in the datadir. */ def.file = os_file_create_simple_no_error_handling( innodb_file_data_key, def.filepath, OS_FILE_OPEN, - OS_FILE_READ_ONLY, &def.success); + OS_FILE_READ_WRITE, &def.success); /* Read the first page of the remote tablespace */ if (def.success) { diff --git a/storage/xtradb/fts/fts0ast.cc b/storage/xtradb/fts/fts0ast.cc index 3a03fc63303..d6c19c0050a 100644 --- a/storage/xtradb/fts/fts0ast.cc +++ b/storage/xtradb/fts/fts0ast.cc @@ -112,9 +112,11 @@ fts_ast_create_node_term( if (str.f_n_char > 0) { /* If the subsequent term (after the first one)'s size - is less than fts_min_token_size, we shall ignore - that. This is to make consistent with MyISAM behavior */ - if (first_node && (str.f_n_char < fts_min_token_size)) { + is less than fts_min_token_size or the term is greater + than fts_max_token_size, we shall ignore that. This is + to make consistent with MyISAM behavior */ + if ((first_node && (str.f_n_char < fts_min_token_size)) + || str.f_n_char > fts_max_token_size) { continue; } @@ -394,6 +396,10 @@ fts_ast_term_set_distance( ulint distance) /*!< in: the text proximity distance */ { + if (node == NULL) { + return; + } + ut_a(node->type == FTS_AST_TEXT); ut_a(node->text.distance == ULINT_UNDEFINED); @@ -551,14 +557,6 @@ fts_ast_visit( break; - case FTS_AST_SUBEXP_LIST: - if (visit_pass != FTS_PASS_FIRST) { - break; - } - - error = fts_ast_visit_sub_exp(node, visitor, arg); - break; - case FTS_AST_OPER: oper = node->oper; oper_node = node; diff --git a/storage/xtradb/fts/fts0blex.cc b/storage/xtradb/fts/fts0blex.cc index dccedac0212..6082261e74c 100644 --- a/storage/xtradb/fts/fts0blex.cc +++ b/storage/xtradb/fts/fts0blex.cc @@ -305,9 +305,9 @@ YY_BUFFER_STATE fts0b_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner YY_BUFFER_STATE fts0b_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); YY_BUFFER_STATE fts0b_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); -void *fts0balloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); -void *fts0brealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); -void fts0bfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +void *fts0balloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +void *fts0brealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +void fts0bfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); #define yy_new_buffer fts0b_create_buffer @@ -347,7 +347,7 @@ typedef int yy_state_type; static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); static int yy_get_next_buffer (yyscan_t yyscanner ); -static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. @@ -579,11 +579,11 @@ extern int fts0bwrap (yyscan_t yyscanner ); #endif #ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); +static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); +static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); #endif #ifndef YY_NO_INPUT @@ -1609,9 +1609,9 @@ YY_BUFFER_STATE fts0b_scan_bytes (yyconst char * yybytes, int _yybytes_len , y #define YY_EXIT_FAILURE 2 #endif -static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { - (void) fprintf( stderr, "%s\n", msg ); + (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } @@ -1910,7 +1910,7 @@ int fts0blex_destroy (yyscan_t yyscanner) */ #ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { register int i; for ( i = 0; i < n; ++i ) @@ -1919,7 +1919,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { register int n; for ( n = 0; s[n]; ++n ) @@ -1929,12 +1929,12 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribu } #endif -void *fts0balloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +void *fts0balloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { return (void *) malloc( size ); } -void *fts0brealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +void *fts0brealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those @@ -1946,7 +1946,7 @@ void *fts0brealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __at return (void *) realloc( (char *) ptr, size ); } -void fts0bfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +void fts0bfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { free( (char *) ptr ); /* see fts0brealloc() for (char *) cast */ } diff --git a/storage/xtradb/fts/fts0config.cc b/storage/xtradb/fts/fts0config.cc index c5cf38ca7f9..5b4ae5c39f7 100644 --- a/storage/xtradb/fts/fts0config.cc +++ b/storage/xtradb/fts/fts0config.cc @@ -151,7 +151,9 @@ fts_config_create_index_param_name( strcpy(name, param); name[len] = '_'; - fts_write_object_id(index->id, name + len + 1); + fts_write_object_id(index->id, name + len + 1, + DICT_TF2_FLAG_IS_SET(index->table, + DICT_TF2_FTS_AUX_HEX_NAME)); return(name); } diff --git a/storage/xtradb/fts/fts0fts.cc b/storage/xtradb/fts/fts0fts.cc index 1b114adea1f..47deee8d8e6 100644 --- a/storage/xtradb/fts/fts0fts.cc +++ b/storage/xtradb/fts/fts0fts.cc @@ -1608,7 +1608,8 @@ fts_rename_aux_tables( new_name, old_table_name, trx); DBUG_EXECUTE_IF("fts_rename_failure", - err = DB_DEADLOCK;); + err = DB_DEADLOCK; + fts_sql_rollback(trx);); mem_free(old_table_name); @@ -1949,7 +1950,7 @@ fts_create_one_index_table( ut_ad(index->type & DICT_FTS); - new_table = dict_mem_table_create(table_name, 0, 5, 1, 0); + new_table = dict_mem_table_create(table_name, 0, 5, 1, 0, false); field = dict_index_get_nth_field(index, 0); charset = innobase_get_fts_charset( @@ -2018,7 +2019,7 @@ fts_create_index_tables_low( fts_table.index_id = index->id; fts_table.table_id = table_id; fts_table.parent = table_name; - fts_table.table = NULL; + fts_table.table = index->table; #ifdef FTS_DOC_STATS_DEBUG char* sql; @@ -4479,7 +4480,7 @@ fts_sync_table( ut_ad(table->fts); - if (table->fts->cache) { + if (!dict_table_is_discarded(table) && table->fts->cache) { err = fts_sync(table->fts->cache->sync); } @@ -4506,15 +4507,11 @@ fts_process_token( fts_string_t str; ulint offset = 0; fts_doc_t* result_doc; - byte buf[FTS_MAX_WORD_LEN + 1]; - - str.f_str = buf; /* Determine where to save the result. */ result_doc = (result) ? result : doc; /* The length of a string in characters is set here only. */ - ret = innobase_mysql_fts_get_token( doc->charset, doc->text.f_str + start_pos, doc->text.f_str + doc->text.f_len, &str, &offset); @@ -4545,6 +4542,7 @@ fts_process_token( (char*) t_str.f_str, t_str.f_len); t_str.f_len = newlen; + t_str.f_str[newlen] = 0; /* Add the word to the document statistics. If the word hasn't been seen before we create a new entry for it. */ @@ -5797,7 +5795,7 @@ fts_is_aux_table_name( my_name[len] = 0; end = my_name + len; - ptr = static_cast(memchr(my_name, '/', len)); + ptr = static_cast(memchr(my_name, '/', len)); if (ptr != NULL) { /* We will start the match after the '/' */ @@ -5940,6 +5938,374 @@ fts_read_tables( return(TRUE); } +/******************************************************************//** +Callback that sets a hex formatted FTS table's flags2 in +SYS_TABLES. The flags is stored in MIX_LEN column. +@return FALSE if all OK */ +static +ibool +fts_set_hex_format( +/*===============*/ + void* row, /*!< in: sel_node_t* */ + void* user_arg) /*!< in: bool set/unset flag */ +{ + sel_node_t* node = static_cast(row); + dfield_t* dfield = que_node_get_val(node->select_list); + + ut_ad(dtype_get_mtype(dfield_get_type(dfield)) == DATA_INT); + ut_ad(dfield_get_len(dfield) == sizeof(ib_uint32_t)); + /* There should be at most one matching record. So the value + must be the default value. */ + ut_ad(mach_read_from_4(static_cast(user_arg)) + == ULINT32_UNDEFINED); + + ulint flags2 = mach_read_from_4( + static_cast(dfield_get_data(dfield))); + + flags2 |= DICT_TF2_FTS_AUX_HEX_NAME; + + mach_write_to_4(static_cast(user_arg), flags2); + + return(FALSE); +} + +/*****************************************************************//** +Update the DICT_TF2_FTS_AUX_HEX_NAME flag in SYS_TABLES. +@return DB_SUCCESS or error code. */ +UNIV_INTERN +dberr_t +fts_update_hex_format_flag( +/*=======================*/ + trx_t* trx, /*!< in/out: transaction that + covers the update */ + table_id_t table_id, /*!< in: Table for which we want + to set the root table->flags2 */ + bool dict_locked) /*!< in: set to true if the + caller already owns the + dict_sys_t::mutex. */ +{ + pars_info_t* info; + ib_uint32_t flags2; + + static const char sql[] = + "PROCEDURE UPDATE_HEX_FORMAT_FLAG() IS\n" + "DECLARE FUNCTION my_func;\n" + "DECLARE CURSOR c IS\n" + " SELECT MIX_LEN " + " FROM SYS_TABLES " + " WHERE ID = :table_id FOR UPDATE;" + "\n" + "BEGIN\n" + "OPEN c;\n" + "WHILE 1 = 1 LOOP\n" + " FETCH c INTO my_func();\n" + " IF c % NOTFOUND THEN\n" + " EXIT;\n" + " END IF;\n" + "END LOOP;\n" + "UPDATE SYS_TABLES" + " SET MIX_LEN = :flags2" + " WHERE ID = :table_id;\n" + "CLOSE c;\n" + "END;\n"; + + flags2 = ULINT32_UNDEFINED; + + info = pars_info_create(); + + pars_info_add_ull_literal(info, "table_id", table_id); + pars_info_bind_int4_literal(info, "flags2", &flags2); + + pars_info_bind_function( + info, "my_func", fts_set_hex_format, &flags2); + + if (trx_get_dict_operation(trx) == TRX_DICT_OP_NONE) { + trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); + } + + dberr_t err = que_eval_sql(info, sql, !dict_locked, trx); + + ut_a(flags2 != ULINT32_UNDEFINED); + + return (err); +} + +#ifdef _WIN32 + +/*********************************************************************//** +Rename an aux table to HEX format. It's called when "%016llu" is used +to format an object id in table name, which only happens in Windows. */ +static __attribute__((nonnull, warn_unused_result)) +dberr_t +fts_rename_one_aux_table_to_hex_format( +/*===================================*/ + trx_t* trx, /*!< in: transaction */ + const fts_aux_table_t* aux_table, /*!< in: table info */ + const dict_table_t* parent_table) /*!< in: parent table name */ +{ + const char* ptr; + fts_table_t fts_table; + char* new_name; + dberr_t error; + + ptr = strchr(aux_table->name, '/'); + ut_a(ptr != NULL); + ++ptr; + /* Skip "FTS_", table id and underscore */ + for (ulint i = 0; i < 2; ++i) { + ptr = strchr(ptr, '_'); + ut_a(ptr != NULL); + ++ptr; + } + + fts_table.suffix = NULL; + if (aux_table->index_id == 0) { + fts_table.type = FTS_COMMON_TABLE; + + for (ulint i = 0; fts_common_tables[i] != NULL; ++i) { + if (strcmp(ptr, fts_common_tables[i]) == 0) { + fts_table.suffix = fts_common_tables[i]; + break; + } + } + } else { + fts_table.type = FTS_INDEX_TABLE; + + /* Skip index id and underscore */ + ptr = strchr(ptr, '_'); + ut_a(ptr != NULL); + ++ptr; + + for (ulint i = 0; fts_index_selector[i].value; ++i) { + if (strcmp(ptr, fts_get_suffix(i)) == 0) { + fts_table.suffix = fts_get_suffix(i); + break; + } + } + } + + ut_a(fts_table.suffix != NULL); + + fts_table.parent = parent_table->name; + fts_table.table_id = aux_table->parent_id; + fts_table.index_id = aux_table->index_id; + fts_table.table = parent_table; + + new_name = fts_get_table_name(&fts_table); + ut_ad(strcmp(new_name, aux_table->name) != 0); + + if (trx_get_dict_operation(trx) == TRX_DICT_OP_NONE) { + trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); + } + + error = row_rename_table_for_mysql(aux_table->name, new_name, trx, + FALSE); + + if (error != DB_SUCCESS) { + ib_logf(IB_LOG_LEVEL_WARN, + "Failed to rename aux table \'%s\' to " + "new format \'%s\'. ", + aux_table->name, new_name); + } else { + ib_logf(IB_LOG_LEVEL_INFO, + "Renamed aux table \'%s\' to \'%s\'.", + aux_table->name, new_name); + } + + mem_free(new_name); + + return (error); +} + +/**********************************************************************//** +Rename all aux tables of a parent table to HEX format. Also set aux tables' +flags2 and parent table's flags2 with DICT_TF2_FTS_AUX_HEX_NAME. +It's called when "%016llu" is used to format an object id in table name, +which only happens in Windows. +Note the ids in tables are correct but the names are old ambiguous ones. + +This function should make sure that either all the parent table and aux tables +are set DICT_TF2_FTS_AUX_HEX_NAME with flags2 or none of them are set */ +static __attribute__((nonnull, warn_unused_result)) +dberr_t +fts_rename_aux_tables_to_hex_format( +/*================================*/ + trx_t* trx, /*!< in: transaction */ + dict_table_t* parent_table, /*!< in: parent table */ + ib_vector_t* tables) /*!< in: aux tables to rename. */ +{ + dberr_t error; + ulint count; + + ut_ad(!DICT_TF2_FLAG_IS_SET(parent_table, DICT_TF2_FTS_AUX_HEX_NAME)); + ut_ad(!ib_vector_is_empty(tables)); + + error = fts_update_hex_format_flag(trx, parent_table->id, true); + + if (error != DB_SUCCESS) { + ib_logf(IB_LOG_LEVEL_WARN, + "Setting parent table %s to hex format failed.", + parent_table->name); + + fts_sql_rollback(trx); + return (error); + } + + DICT_TF2_FLAG_SET(parent_table, DICT_TF2_FTS_AUX_HEX_NAME); + + for (count = 0; count < ib_vector_size(tables); ++count) { + dict_table_t* table; + fts_aux_table_t* aux_table; + + aux_table = static_cast( + ib_vector_get(tables, count)); + + table = dict_table_open_on_id(aux_table->id, TRUE, + DICT_TABLE_OP_NORMAL); + + ut_ad(table != NULL); + ut_ad(!DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_AUX_HEX_NAME)); + + /* Set HEX_NAME flag here to make sure we can get correct + new table name in following function */ + DICT_TF2_FLAG_SET(table, DICT_TF2_FTS_AUX_HEX_NAME); + error = fts_rename_one_aux_table_to_hex_format(trx, + aux_table, parent_table); + /* We will rollback the trx if the error != DB_SUCCESS, + so setting the flag here is the same with setting it in + row_rename_table_for_mysql */ + DBUG_EXECUTE_IF("rename_aux_table_fail", error = DB_ERROR;); + + if (error != DB_SUCCESS) { + dict_table_close(table, TRUE, FALSE); + + ib_logf(IB_LOG_LEVEL_WARN, + "Failed to rename one aux table %s " + "Will revert all successful rename " + "operations.", aux_table->name); + + fts_sql_rollback(trx); + break; + } + + error = fts_update_hex_format_flag(trx, aux_table->id, true); + dict_table_close(table, TRUE, FALSE); + + if (error != DB_SUCCESS) { + ib_logf(IB_LOG_LEVEL_WARN, + "Setting aux table %s to hex format failed.", + aux_table->name); + + fts_sql_rollback(trx); + break; + } + } + + if (error != DB_SUCCESS) { + ut_ad(count != ib_vector_size(tables)); + /* If rename fails, thr trx would be rolled back, we can't + use it any more, we'll start a new background trx to do + the reverting. */ + ut_a(trx->state == TRX_STATE_NOT_STARTED); + bool not_rename = false; + + /* Try to revert those succesful rename operations + in order to revert the ibd file rename. */ + for (ulint i = 0; i <= count; ++i) { + dict_table_t* table; + fts_aux_table_t* aux_table; + trx_t* trx_bg; + dberr_t err; + + aux_table = static_cast( + ib_vector_get(tables, i)); + + table = dict_table_open_on_id(aux_table->id, TRUE, + DICT_TABLE_OP_NORMAL); + ut_ad(table != NULL); + + if (not_rename) { + DICT_TF2_FLAG_UNSET(table, + DICT_TF2_FTS_AUX_HEX_NAME); + } + + if (!DICT_TF2_FLAG_IS_SET(table, + DICT_TF2_FTS_AUX_HEX_NAME)) { + dict_table_close(table, TRUE, FALSE); + continue; + } + + trx_bg = trx_allocate_for_background(); + trx_bg->op_info = "Revert half done rename"; + trx_bg->dict_operation_lock_mode = RW_X_LATCH; + trx_start_for_ddl(trx_bg, TRX_DICT_OP_TABLE); + + DICT_TF2_FLAG_UNSET(table, DICT_TF2_FTS_AUX_HEX_NAME); + err = row_rename_table_for_mysql(table->name, + aux_table->name, + trx_bg, FALSE); + + trx_bg->dict_operation_lock_mode = 0; + dict_table_close(table, TRUE, FALSE); + + if (err != DB_SUCCESS) { + ib_logf(IB_LOG_LEVEL_WARN, "Failed to revert " + "table %s. Please revert manually.", + table->name); + fts_sql_rollback(trx_bg); + /* Continue to clear aux tables' flags2 */ + not_rename = true; + continue; + } + + fts_sql_commit(trx_bg); + } + + DICT_TF2_FLAG_UNSET(parent_table, DICT_TF2_FTS_AUX_HEX_NAME); + } + + return (error); +} + +/**********************************************************************//** +Convert an id, which is actually a decimal number but was regard as a HEX +from a string, to its real value. */ +static +ib_id_t +fts_fake_hex_to_dec( +/*================*/ + ib_id_t id) /*!< in: number to convert */ +{ + ib_id_t dec_id = 0; + char tmp_id[FTS_AUX_MIN_TABLE_ID_LENGTH]; + int ret; + + ret = sprintf(tmp_id, UINT64PFx, id); + ut_ad(ret == 16); + ret = sscanf(tmp_id, "%016llu", &dec_id); + ut_ad(ret == 1); + + return dec_id; +} + +/*********************************************************************//** +Compare two fts_aux_table_t parent_ids. +@return < 0 if n1 < n2, 0 if n1 == n2, > 0 if n1 > n2 */ +UNIV_INLINE +int +fts_check_aux_table_parent_id_cmp( +/*==============================*/ + const void* p1, /*!< in: id1 */ + const void* p2) /*!< in: id2 */ +{ + const fts_aux_table_t* fa1 = static_cast(p1); + const fts_aux_table_t* fa2 = static_cast(p2); + + return static_cast(fa1->parent_id - fa2->parent_id); +} + +#endif /* _WIN32 */ + /**********************************************************************//** Check and drop all orphaned FTS auxiliary tables, those that don't have a parent table or FTS index defined on them. @@ -5951,18 +6317,75 @@ fts_check_and_drop_orphaned_tables( trx_t* trx, /*!< in: transaction */ ib_vector_t* tables) /*!< in: tables to check */ { +#ifdef _WIN32 + mem_heap_t* heap; + ib_vector_t* aux_tables_to_rename; + ib_alloc_t* heap_alloc; + + heap = mem_heap_create(1024); + heap_alloc = ib_heap_allocator_create(heap); + + /* We store all aux tables belonging to the same parent table here, + and rename all these tables in a batch mode. */ + aux_tables_to_rename = ib_vector_create(heap_alloc, + sizeof(fts_aux_table_t), 128); + + /* Sort by parent_id first, in case rename will fail */ + ib_vector_sort(tables, fts_check_aux_table_parent_id_cmp); +#endif /* _WIN32 */ + for (ulint i = 0; i < ib_vector_size(tables); ++i) { - dict_table_t* table; + dict_table_t* parent_table; fts_aux_table_t* aux_table; bool drop = false; +#ifdef _WIN32 + dict_table_t* table; + fts_aux_table_t* next_aux_table = NULL; + ib_id_t orig_parent_id = 0; + bool rename = false; +#endif /* _WIN32 */ aux_table = static_cast( ib_vector_get(tables, i)); +#ifdef _WIN32 table = dict_table_open_on_id( + aux_table->id, TRUE, DICT_TABLE_OP_NORMAL); + orig_parent_id = aux_table->parent_id; + + if (table == NULL || strcmp(table->name, aux_table->name)) { + /* Skip these aux tables, which are common tables + with wrong table ids */ + if (table) { + dict_table_close(table, TRUE, FALSE); + } + + continue; + + } else if (!DICT_TF2_FLAG_IS_SET(table, + DICT_TF2_FTS_AUX_HEX_NAME)) { + + aux_table->parent_id = fts_fake_hex_to_dec( + aux_table->parent_id); + + if (aux_table->index_id != 0) { + aux_table->index_id = fts_fake_hex_to_dec( + aux_table->index_id); + } + + ut_ad(aux_table->id > aux_table->parent_id); + rename = true; + } + + if (table) { + dict_table_close(table, TRUE, FALSE); + } +#endif /* _WIN32 */ + + parent_table = dict_table_open_on_id( aux_table->parent_id, TRUE, DICT_TABLE_OP_NORMAL); - if (table == NULL || table->fts == NULL) { + if (parent_table == NULL || parent_table->fts == NULL) { drop = true; @@ -5971,7 +6394,7 @@ fts_check_and_drop_orphaned_tables( fts_t* fts; drop = true; - fts = table->fts; + fts = parent_table->fts; id = aux_table->index_id; /* Search for the FT index in the table's list. */ @@ -5979,33 +6402,28 @@ fts_check_and_drop_orphaned_tables( j < ib_vector_size(fts->indexes); ++j) { - const dict_index_t* index; + const dict_index_t* index; index = static_cast( ib_vector_getp_const(fts->indexes, j)); if (index->id == id) { - drop = false; break; } } } - if (table) { - dict_table_close(table, TRUE, FALSE); - } - if (drop) { ib_logf(IB_LOG_LEVEL_WARN, "Parent table of FTS auxiliary table %s not " "found.", aux_table->name); - dberr_t err = fts_drop_table(trx, aux_table->name); + dberr_t err = fts_drop_table(trx, aux_table->name); if (err == DB_FAIL) { - char* path; + char* path; path = fil_make_ibd_name( aux_table->name, false); @@ -6016,7 +6434,120 @@ fts_check_and_drop_orphaned_tables( mem_free(path); } } +#ifdef _WIN32 + if (!drop && rename) { + ib_vector_push(aux_tables_to_rename, aux_table); + } + + if (i + 1 < ib_vector_size(tables)) { + next_aux_table = static_cast( + ib_vector_get(tables, i + 1)); + } + + if ((next_aux_table == NULL + || orig_parent_id != next_aux_table->parent_id) + && !ib_vector_is_empty(aux_tables_to_rename)) { + /* All aux tables of parent table, whose id is + last_parent_id, have been checked, try to rename + them if necessary. We had better use a new background + trx to rename rather than the original trx, in case + any failure would cause a complete rollback. */ + dberr_t err; + trx_t* trx_rename = trx_allocate_for_background(); + trx_rename->op_info = "Rename aux tables to " + "hex format"; + trx_rename->dict_operation_lock_mode = RW_X_LATCH; + trx_start_for_ddl(trx_rename, TRX_DICT_OP_TABLE); + + err = fts_rename_aux_tables_to_hex_format(trx_rename, + parent_table, aux_tables_to_rename); + + trx_rename->dict_operation_lock_mode = 0; + + if (err != DB_SUCCESS) { + ib_logf(IB_LOG_LEVEL_WARN, + "Rollback operations on all " + "aux tables of table %s. " + "Please check why renaming aux tables " + "failed, and restart the server to " + "upgrade again to " + "get the table work.", + parent_table->name); + + fts_sql_rollback(trx_rename); + } else { + fts_sql_commit(trx_rename); + } + + trx_free_for_background(trx_rename); + ib_vector_reset(aux_tables_to_rename); + } +#else /* _WIN32 */ + if (!drop) { + dict_table_t* table; + + table = dict_table_open_on_id( + aux_table->id, TRUE, DICT_TABLE_OP_NORMAL); + if (table != NULL + && strcmp(table->name, aux_table->name)) { + dict_table_close(table, TRUE, FALSE); + table = NULL; + } + + if (table != NULL + && !DICT_TF2_FLAG_IS_SET( + table, + DICT_TF2_FTS_AUX_HEX_NAME)) { + dberr_t err = fts_update_hex_format_flag( + trx, table->id, true); + + if (err != DB_SUCCESS) { + ib_logf(IB_LOG_LEVEL_WARN, + "Setting aux table %s to hex " + "format failed.", table->name); + } else { + DICT_TF2_FLAG_SET(table, + DICT_TF2_FTS_AUX_HEX_NAME); + } + } + + if (table != NULL) { + dict_table_close(table, TRUE, FALSE); + } + + ut_ad(parent_table != NULL); + if (!DICT_TF2_FLAG_IS_SET(parent_table, + DICT_TF2_FTS_AUX_HEX_NAME)) { + dberr_t err = fts_update_hex_format_flag( + trx, parent_table->id, true); + + if (err != DB_SUCCESS) { + ib_logf(IB_LOG_LEVEL_WARN, + "Setting parent table %s of " + "FTS auxiliary %s to hex " + "format failed.", + parent_table->name, + aux_table->name); + } else { + DICT_TF2_FLAG_SET(parent_table, + DICT_TF2_FTS_AUX_HEX_NAME); + } + } + } + +#endif /* _WIN32 */ + + if (parent_table) { + dict_table_close(parent_table, TRUE, FALSE); + } } + +#ifdef _WIN32 + /* Free the memory allocated at the beginning */ + if (heap != NULL) { + mem_heap_free(heap); + } +#endif /* _WIN32 */ } /**********************************************************************//** diff --git a/storage/xtradb/fts/fts0opt.cc b/storage/xtradb/fts/fts0opt.cc index 7cdad522564..2efb5d05c21 100644 --- a/storage/xtradb/fts/fts0opt.cc +++ b/storage/xtradb/fts/fts0opt.cc @@ -1624,10 +1624,12 @@ fts_optimize_create( optim->fts_common_table.parent = table->name; optim->fts_common_table.table_id = table->id; optim->fts_common_table.type = FTS_COMMON_TABLE; + optim->fts_common_table.table = table; optim->fts_index_table.parent = table->name; optim->fts_index_table.table_id = table->id; optim->fts_index_table.type = FTS_INDEX_TABLE; + optim->fts_index_table.table = table; /* The common prefix for all this parent table's aux tables. */ optim->name_prefix = fts_get_table_name_prefix( diff --git a/storage/xtradb/fts/fts0pars.cc b/storage/xtradb/fts/fts0pars.cc index a4009106c83..ef361b3c9c6 100644 --- a/storage/xtradb/fts/fts0pars.cc +++ b/storage/xtradb/fts/fts0pars.cc @@ -467,9 +467,9 @@ static const yytype_int8 yyrhs[] = /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 79, 79, 85, 89, 99, 111, 115, 124, 128, - 132, 136, 141, 147, 152, 159, 165, 169, 173, 177, - 181, 186, 191, 197, 202 + 0, 79, 79, 85, 89, 99, 111, 119, 129, 133, + 137, 141, 146, 152, 157, 164, 170, 174, 178, 182, + 186, 191, 196, 202, 207 }; #endif @@ -1458,7 +1458,7 @@ yyreduce: (yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (2)].node)); if (!(yyval.node)) { - (yyval.node) = fts_ast_create_node_subexp_list(state, (yyvsp[(2) - (2)].node)); + (yyval.node) = (yyvsp[(2) - (2)].node); } else { fts_ast_add_node((yyval.node), (yyvsp[(2) - (2)].node)); } @@ -1471,18 +1471,23 @@ yyreduce: #line 111 "fts0pars.y" { (yyval.node) = (yyvsp[(2) - (3)].node); + + if ((yyval.node)) { + (yyval.node) = fts_ast_create_node_subexp_list(state, (yyval.node)); + } } break; case 7: /* Line 1806 of yacc.c */ -#line 115 "fts0pars.y" +#line 119 "fts0pars.y" { - (yyval.node) = fts_ast_create_node_subexp_list(state, (yyvsp[(1) - (4)].node)); + (yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (4)].node)); if ((yyvsp[(3) - (4)].node)) { - fts_ast_add_node((yyval.node), (yyvsp[(3) - (4)].node)); + fts_ast_add_node((yyval.node), + fts_ast_create_node_subexp_list(state, (yyvsp[(3) - (4)].node))); } } break; @@ -1490,7 +1495,7 @@ yyreduce: case 8: /* Line 1806 of yacc.c */ -#line 124 "fts0pars.y" +#line 129 "fts0pars.y" { (yyval.node) = (yyvsp[(1) - (1)].node); } @@ -1499,7 +1504,7 @@ yyreduce: case 9: /* Line 1806 of yacc.c */ -#line 128 "fts0pars.y" +#line 133 "fts0pars.y" { (yyval.node) = (yyvsp[(1) - (1)].node); } @@ -1508,7 +1513,7 @@ yyreduce: case 10: /* Line 1806 of yacc.c */ -#line 132 "fts0pars.y" +#line 137 "fts0pars.y" { fts_ast_term_set_wildcard((yyvsp[(1) - (2)].node)); } @@ -1517,7 +1522,7 @@ yyreduce: case 11: /* Line 1806 of yacc.c */ -#line 136 "fts0pars.y" +#line 141 "fts0pars.y" { fts_ast_term_set_distance((yyvsp[(1) - (3)].node), strtoul((yyvsp[(3) - (3)].token), NULL, 10)); free((yyvsp[(3) - (3)].token)); @@ -1527,7 +1532,7 @@ yyreduce: case 12: /* Line 1806 of yacc.c */ -#line 141 "fts0pars.y" +#line 146 "fts0pars.y" { (yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (3)].node)); fts_ast_add_node((yyval.node), (yyvsp[(2) - (3)].node)); @@ -1538,7 +1543,7 @@ yyreduce: case 13: /* Line 1806 of yacc.c */ -#line 147 "fts0pars.y" +#line 152 "fts0pars.y" { (yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (2)].node)); fts_ast_add_node((yyval.node), (yyvsp[(2) - (2)].node)); @@ -1548,7 +1553,7 @@ yyreduce: case 14: /* Line 1806 of yacc.c */ -#line 152 "fts0pars.y" +#line 157 "fts0pars.y" { (yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (4)].node)); fts_ast_add_node((yyval.node), (yyvsp[(2) - (4)].node)); @@ -1560,7 +1565,7 @@ yyreduce: case 15: /* Line 1806 of yacc.c */ -#line 159 "fts0pars.y" +#line 164 "fts0pars.y" { (yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (2)].node)); fts_ast_add_node((yyval.node), (yyvsp[(2) - (2)].node)); @@ -1570,7 +1575,7 @@ yyreduce: case 16: /* Line 1806 of yacc.c */ -#line 165 "fts0pars.y" +#line 170 "fts0pars.y" { (yyval.node) = fts_ast_create_node_oper(state, FTS_IGNORE); } @@ -1579,7 +1584,7 @@ yyreduce: case 17: /* Line 1806 of yacc.c */ -#line 169 "fts0pars.y" +#line 174 "fts0pars.y" { (yyval.node) = fts_ast_create_node_oper(state, FTS_EXIST); } @@ -1588,7 +1593,7 @@ yyreduce: case 18: /* Line 1806 of yacc.c */ -#line 173 "fts0pars.y" +#line 178 "fts0pars.y" { (yyval.node) = fts_ast_create_node_oper(state, FTS_NEGATE); } @@ -1597,7 +1602,7 @@ yyreduce: case 19: /* Line 1806 of yacc.c */ -#line 177 "fts0pars.y" +#line 182 "fts0pars.y" { (yyval.node) = fts_ast_create_node_oper(state, FTS_DECR_RATING); } @@ -1606,7 +1611,7 @@ yyreduce: case 20: /* Line 1806 of yacc.c */ -#line 181 "fts0pars.y" +#line 186 "fts0pars.y" { (yyval.node) = fts_ast_create_node_oper(state, FTS_INCR_RATING); } @@ -1614,16 +1619,6 @@ yyreduce: case 21: -/* Line 1806 of yacc.c */ -#line 186 "fts0pars.y" - { - (yyval.node) = fts_ast_create_node_term(state, (yyvsp[(1) - (1)].token)); - free((yyvsp[(1) - (1)].token)); - } - break; - - case 22: - /* Line 1806 of yacc.c */ #line 191 "fts0pars.y" { @@ -1632,10 +1627,20 @@ yyreduce: } break; + case 22: + +/* Line 1806 of yacc.c */ +#line 196 "fts0pars.y" + { + (yyval.node) = fts_ast_create_node_term(state, (yyvsp[(1) - (1)].token)); + free((yyvsp[(1) - (1)].token)); + } + break; + case 23: /* Line 1806 of yacc.c */ -#line 197 "fts0pars.y" +#line 202 "fts0pars.y" { (yyval.node) = (yyvsp[(2) - (2)].node); } @@ -1644,7 +1649,7 @@ yyreduce: case 24: /* Line 1806 of yacc.c */ -#line 202 "fts0pars.y" +#line 207 "fts0pars.y" { (yyval.node) = fts_ast_create_node_text(state, (yyvsp[(1) - (1)].token)); free((yyvsp[(1) - (1)].token)); @@ -1654,7 +1659,7 @@ yyreduce: /* Line 1806 of yacc.c */ -#line 1658 "fts0pars.cc" +#line 1663 "fts0pars.cc" default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1885,7 +1890,7 @@ yyreturn: /* Line 2067 of yacc.c */ -#line 207 "fts0pars.y" +#line 212 "fts0pars.y" /******************************************************************** diff --git a/storage/xtradb/fts/fts0pars.y b/storage/xtradb/fts/fts0pars.y index 73d71bc87c5..ff22e9a9873 100644 --- a/storage/xtradb/fts/fts0pars.y +++ b/storage/xtradb/fts/fts0pars.y @@ -101,7 +101,7 @@ expr_lst: /* Empty */ { $$ = fts_ast_create_node_list(state, $1); if (!$$) { - $$ = fts_ast_create_node_subexp_list(state, $2); + $$ = $2; } else { fts_ast_add_node($$, $2); } @@ -110,13 +110,18 @@ expr_lst: /* Empty */ { sub_expr: '(' expr_lst ')' { $$ = $2; + + if ($$) { + $$ = fts_ast_create_node_subexp_list(state, $$); + } } | prefix '(' expr_lst ')' { - $$ = fts_ast_create_node_subexp_list(state, $1); + $$ = fts_ast_create_node_list(state, $1); if ($3) { - fts_ast_add_node($$, $3); + fts_ast_add_node($$, + fts_ast_create_node_subexp_list(state, $3)); } } ; diff --git a/storage/xtradb/fts/fts0que.cc b/storage/xtradb/fts/fts0que.cc index 7da60c0d166..189c43768cd 100644 --- a/storage/xtradb/fts/fts0que.cc +++ b/storage/xtradb/fts/fts0que.cc @@ -40,9 +40,7 @@ Completed 2011/7/10 Sunny and Jimmy Yang #include "fts0vlc.ic" #endif -#include #include -#include #define FTS_ELEM(t, n, i, j) (t[(i) * n + (j)]) @@ -66,8 +64,7 @@ static const double FTS_NORMALIZE_COEFF = 0.0115F; // FIXME: Need to have a generic iterator that traverses the ilist. -typedef std::map word_map_t; -typedef std::vector word_vector_t; +typedef std::vector word_vector_t; struct fts_word_freq_t; @@ -92,7 +89,7 @@ struct fts_query_t { fts_ast_node_t* cur_node; /*!< Current tree node */ - word_map_t* word_map; /*!< Matched word map for + ib_rbt_t* word_map; /*!< Matched word map for searching by word*/ word_vector_t* word_vector; /*!< Matched word vector for @@ -229,7 +226,7 @@ struct fts_doc_freq_t { /** To determine the word frequency per document. */ struct fts_word_freq_t { - byte* word; /*!< Word for which we need the freq, + fts_string_t word; /*!< Word for which we need the freq, it's allocated on the query heap */ ib_rbt_t* doc_freqs; /*!< RB Tree for storing per document @@ -257,15 +254,14 @@ static dberr_t fts_query_filter_doc_ids( /*=====================*/ - fts_query_t* query, /*!< in: query instance */ - const byte* word, /*!< in: the current word */ - fts_word_freq_t*word_freq, /*!< in/out: word frequency */ - const fts_node_t* - node, /*!< in: current FTS node */ - void* data, /*!< in: doc id ilist */ - ulint len, /*!< in: doc id ilist size */ - ibool calc_doc_count);/*!< in: whether to remember doc - count */ + fts_query_t* query, /*!< in: query instance */ + const fts_string_t* word, /*!< in: the current word */ + fts_word_freq_t* word_freq, /*!< in/out: word frequency */ + const fts_node_t* node, /*!< in: current FTS node */ + void* data, /*!< in: doc id ilist */ + ulint len, /*!< in: doc id ilist size */ + ibool calc_doc_count);/*!< in: whether to remember doc + count */ #if 0 /*****************************************************************//*** @@ -575,27 +571,41 @@ static void fts_ranking_words_add( /*==================*/ - fts_query_t* query, /*!< in: query instance */ - fts_ranking_t* ranking, /*!< in: ranking instance */ - const char* word) /*!< in: term/word to add */ + fts_query_t* query, /*!< in: query instance */ + fts_ranking_t* ranking, /*!< in: ranking instance */ + const fts_string_t* word) /*!< in: term/word to add */ { ulint pos; ulint byte_offset; ulint bit_offset; - word_map_t::iterator it; + ib_rbt_bound_t parent; - /* Note: we suppose the word map and vector are append-only */ - /* Check if need to add it to word map */ - it = query->word_map->lower_bound(word); - if (it != query->word_map->end() - && !query->word_map->key_comp()(word, it->first)) { - pos = it->second; + /* Note: we suppose the word map and vector are append-only. */ + ut_ad(query->word_vector->size() == rbt_size(query->word_map)); + + /* We use ib_rbt to simulate a map, f_n_char means position. */ + if (rbt_search(query->word_map, &parent, word) == 0) { + fts_string_t* result_word; + + result_word = rbt_value(fts_string_t, parent.last); + pos = result_word->f_n_char; + ut_ad(pos < rbt_size(query->word_map)); } else { - pos = query->word_map->size(); - query->word_map->insert(it, - std::pair(word, pos)); + /* Add the word to map. */ + fts_string_t new_word; - query->word_vector->push_back(word); + pos = rbt_size(query->word_map); + + new_word.f_str = static_cast(mem_heap_alloc(query->heap, + word->f_len + 1)); + memcpy(new_word.f_str, word->f_str, word->f_len); + new_word.f_str[word->f_len] = 0; + new_word.f_len = word->f_len; + new_word.f_n_char = pos; + + rbt_add_node(query->word_map, &parent, &new_word); + ut_ad(rbt_validate(query->word_map)); + query->word_vector->push_back(new_word); } /* Check words len */ @@ -630,7 +640,7 @@ fts_ranking_words_get_next( const fts_query_t* query, /*!< in: query instance */ fts_ranking_t* ranking,/*!< in: ranking instance */ ulint* pos, /*!< in/out: word start pos */ - byte** word) /*!< in/out: term/word to add */ + fts_string_t* word) /*!< in/out: term/word to add */ { bool ret = false; ulint max_pos = ranking->words_len * CHAR_BIT; @@ -651,7 +661,7 @@ fts_ranking_words_get_next( /* Get next word from word vector */ if (ret) { ut_ad(*pos < query->word_vector->size()); - *word = (byte*)query->word_vector->at((size_t)*pos).c_str(); + *word = query->word_vector->at((size_t)*pos); *pos += 1; } @@ -666,23 +676,22 @@ static fts_word_freq_t* fts_query_add_word_freq( /*====================*/ - fts_query_t* query, /*!< in: query instance */ - const byte* word) /*!< in: term/word to add */ + fts_query_t* query, /*!< in: query instance */ + const fts_string_t* word) /*!< in: term/word to add */ { ib_rbt_bound_t parent; /* Lookup the word in our rb tree and add if it doesn't exist. */ if (rbt_search(query->word_freqs, &parent, word) != 0) { fts_word_freq_t word_freq; - ulint len = ut_strlen((char*) word) + 1; memset(&word_freq, 0, sizeof(word_freq)); - word_freq.word = static_cast( - mem_heap_alloc(query->heap, len)); - - /* Need to copy the NUL character too. */ - memcpy(word_freq.word, word, len); + word_freq.word.f_str = static_cast( + mem_heap_alloc(query->heap, word->f_len + 1)); + memcpy(word_freq.word.f_str, word->f_str, word->f_len); + word_freq.word.f_str[word->f_len] = 0; + word_freq.word.f_len = word->f_len; word_freq.doc_count = 0; @@ -692,7 +701,7 @@ fts_query_add_word_freq( parent.last = rbt_add_node( query->word_freqs, &parent, &word_freq); - query->total_size += len + query->total_size += word->f_len + SIZEOF_RBT_CREATE + SIZEOF_RBT_NODE_ADD + sizeof(fts_word_freq_t); @@ -956,7 +965,7 @@ fts_query_add_word_to_document( /*===========================*/ fts_query_t* query, /*!< in: query to update */ doc_id_t doc_id, /*!< in: the document to update */ - const byte* word) /*!< in: the token to add */ + const fts_string_t* word) /*!< in: the token to add */ { ib_rbt_bound_t parent; fts_ranking_t* ranking = NULL; @@ -980,7 +989,7 @@ fts_query_add_word_to_document( } if (ranking != NULL) { - fts_ranking_words_add(query, ranking, (char*)word); + fts_ranking_words_add(query, ranking, word); } } @@ -1010,13 +1019,13 @@ fts_query_check_node( fts_word_freq_t*word_freqs; /* The word must exist. */ - ret = rbt_search(query->word_freqs, &parent, token->f_str); + ret = rbt_search(query->word_freqs, &parent, token); ut_a(ret == 0); word_freqs = rbt_value(fts_word_freq_t, parent.last); query->error = fts_query_filter_doc_ids( - query, token->f_str, word_freqs, node, + query, token, word_freqs, node, node->ilist, ilist_size, TRUE); } } @@ -1073,7 +1082,7 @@ fts_cache_find_wildcard( ret = rbt_search(query->word_freqs, &freq_parent, - srch_text.f_str); + &srch_text); ut_a(ret == 0); @@ -1082,7 +1091,7 @@ fts_cache_find_wildcard( freq_parent.last); query->error = fts_query_filter_doc_ids( - query, srch_text.f_str, + query, &srch_text, word_freqs, node, node->ilist, node->ilist_size, TRUE); @@ -1542,7 +1551,7 @@ fts_merge_doc_ids( for (node = rbt_first(doc_ids); node; node = rbt_next(doc_ids, node)) { fts_ranking_t* ranking; ulint pos = 0; - byte* word = NULL; + fts_string_t word; ranking = rbt_value(fts_ranking_t, node); @@ -1557,7 +1566,7 @@ fts_merge_doc_ids( ut_a(ranking->words); while (fts_ranking_words_get_next(query, ranking, &pos, &word)) { fts_query_add_word_to_document(query, ranking->doc_id, - word); + &word); } } @@ -2472,8 +2481,7 @@ fts_query_search_phrase( token = static_cast( ib_vector_get(tokens, z)); fts_query_add_word_to_document( - query, match->doc_id, - token->f_str); + query, match->doc_id, token); } } } @@ -2562,7 +2570,7 @@ fts_query_phrase_search( && result_str.f_n_char <= fts_max_token_size) { /* Add the word to the RB tree so that we can calculate it's frequencey within a document. */ - fts_query_add_word_freq(query, token->f_str); + fts_query_add_word_freq(query, token); } else { ib_vector_pop(tokens); } @@ -2687,7 +2695,7 @@ fts_query_phrase_search( } fts_query_add_word_to_document( - query, match->doc_id, token->f_str); + query, match->doc_id, token); } query->oper = oper; goto func_exit; @@ -2837,6 +2845,8 @@ fts_query_visitor( ut_ad(query->intersection == NULL); query->intersection = rbt_create( sizeof(fts_ranking_t), fts_ranking_doc_id_cmp); + + query->total_size += SIZEOF_RBT_CREATE; } /* Set the current proximity distance. */ @@ -2858,10 +2868,12 @@ fts_query_visitor( break; case FTS_AST_TERM: + token.f_str = node->term.ptr; + token.f_len = ut_strlen(reinterpret_cast(token.f_str)); /* Add the word to our RB tree that will be used to calculate this terms per document frequency. */ - fts_query_add_word_freq(query, node->term.ptr); + fts_query_add_word_freq(query, &token); ptr = fts_query_get_token(node, &token); query->error = fts_query_execute(query, &token); @@ -2871,6 +2883,10 @@ fts_query_visitor( } break; + case FTS_AST_SUBEXP_LIST: + query->error = fts_ast_visit_sub_exp(node, fts_query_visitor, arg); + break; + default: ut_error; } @@ -2905,13 +2921,7 @@ fts_ast_visit_sub_exp( ut_a(node->type == FTS_AST_SUBEXP_LIST); - node = node->list.head; - - if (!node || !node->next) { - return(error); - } - - cur_oper = node->oper; + cur_oper = query->oper; /* Save current result set */ parent_doc_ids = query->doc_ids; @@ -2927,26 +2937,20 @@ fts_ast_visit_sub_exp( query->multi_exist = false; /* Process nodes in current sub-expression and store its result set in query->doc_ids we created above. */ - error = fts_ast_visit(FTS_NONE, node->next, visitor, + error = fts_ast_visit(FTS_NONE, node, visitor, arg, &will_be_ignored); - /* Reinstate parent node state and prepare for merge. */ + /* Reinstate parent node state */ query->multi_exist = multi_exist; query->oper = cur_oper; - subexpr_doc_ids = query->doc_ids; - - /* Restore current result set. */ - query->doc_ids = parent_doc_ids; /* Merge the sub-expression result with the parent result set. */ + subexpr_doc_ids = query->doc_ids; + query->doc_ids = parent_doc_ids; if (error == DB_SUCCESS && !rbt_empty(subexpr_doc_ids)) { error = fts_merge_doc_ids(query, subexpr_doc_ids); } - if (query->oper == FTS_EXIST) { - query->multi_exist = true; - } - /* Free current result set. Result already merged into parent. */ fts_query_free_doc_ids(query, subexpr_doc_ids); @@ -3033,14 +3037,13 @@ static dberr_t fts_query_filter_doc_ids( /*=====================*/ - fts_query_t* query, /*!< in: query instance */ - const byte* word, /*!< in: the current word */ - fts_word_freq_t*word_freq, /*!< in/out: word frequency */ - const fts_node_t* - node, /*!< in: current FTS node */ - void* data, /*!< in: doc id ilist */ - ulint len, /*!< in: doc id ilist size */ - ibool calc_doc_count) /*!< in: whether to remember doc count */ + fts_query_t* query, /*!< in: query instance */ + const fts_string_t* word, /*!< in: the current word */ + fts_word_freq_t* word_freq, /*!< in/out: word frequency */ + const fts_node_t* node, /*!< in: current FTS node */ + void* data, /*!< in: doc id ilist */ + ulint len, /*!< in: doc id ilist size */ + ibool calc_doc_count) /*!< in: whether to remember doc count */ { byte* ptr = static_cast(data); doc_id_t doc_id = 0; @@ -3163,13 +3166,15 @@ fts_query_read_node( ib_rbt_bound_t parent; fts_word_freq_t* word_freq; ibool skip = FALSE; - byte term[FTS_MAX_WORD_LEN + 1]; + fts_string_t term; + byte buf[FTS_MAX_WORD_LEN + 1]; dberr_t error = DB_SUCCESS; ut_a(query->cur_node->type == FTS_AST_TERM || query->cur_node->type == FTS_AST_TEXT); memset(&node, 0, sizeof(node)); + term.f_str = buf; /* Need to consider the wildcard search case, the word frequency is created on the search string not the actual word. So we need @@ -3179,15 +3184,18 @@ fts_query_read_node( /* These cast are safe since we only care about the terminating NUL character as an end of string marker. */ - ut_strcpy((char*) term, (char*) query->cur_node->term.ptr); + term.f_len = ut_strlen(reinterpret_cast + (query->cur_node->term.ptr)); + ut_ad(FTS_MAX_WORD_LEN >= term.f_len); + memcpy(term.f_str, query->cur_node->term.ptr, term.f_len); } else { - /* Need to copy the NUL character too. */ - memcpy(term, word->f_str, word->f_len); - term[word->f_len] = 0; + term.f_len = word->f_len; + ut_ad(FTS_MAX_WORD_LEN >= word->f_len); + memcpy(term.f_str, word->f_str, word->f_len); } /* Lookup the word in our rb tree, it must exist. */ - ret = rbt_search(query->word_freqs, &parent, term); + ret = rbt_search(query->word_freqs, &parent, &term); ut_a(ret == 0); @@ -3239,7 +3247,7 @@ fts_query_read_node( case 4: /* ILIST */ error = fts_query_filter_doc_ids( - query, word_freq->word, word_freq, + query, &word_freq->word, word_freq, &node, data, len, FALSE); break; @@ -3332,7 +3340,7 @@ fts_query_calculate_idf( if (fts_enable_diag_print) { fprintf(stderr,"'%s' -> " UINT64PF "/" UINT64PF " %6.5lf\n", - word_freq->word, + word_freq->word.f_str, query->total_docs, word_freq->doc_count, word_freq->idf); } @@ -3349,12 +3357,12 @@ fts_query_calculate_ranking( fts_ranking_t* ranking) /*!< in: Document to rank */ { ulint pos = 0; - byte* word = NULL; + fts_string_t word; /* At this stage, ranking->rank should not exceed the 1.0 bound */ ut_ad(ranking->rank <= 1.0 && ranking->rank >= -1.0); - ut_ad(query->word_map->size() == query->word_vector->size()); + ut_ad(rbt_size(query->word_map) == query->word_vector->size()); while (fts_ranking_words_get_next(query, ranking, &pos, &word)) { int ret; @@ -3363,8 +3371,7 @@ fts_query_calculate_ranking( fts_doc_freq_t* doc_freq; fts_word_freq_t* word_freq; - ut_ad(word != NULL); - ret = rbt_search(query->word_freqs, &parent, word); + ret = rbt_search(query->word_freqs, &parent, &word); /* It must exist. */ ut_a(ret == 0); @@ -3620,18 +3627,18 @@ fts_query_free( ut_a(!query->intersection); - if (query->heap) { - mem_heap_free(query->heap); - } - if (query->word_map) { - delete query->word_map; + rbt_free(query->word_map); } if (query->word_vector) { delete query->word_vector; } + if (query->heap) { + mem_heap_free(query->heap); + } + memset(query, 0, sizeof(*query)); } @@ -3820,6 +3827,7 @@ fts_query( query.fts_common_table.type = FTS_COMMON_TABLE; query.fts_common_table.table_id = index->table->id; query.fts_common_table.parent = index->table->name; + query.fts_common_table.table = index->table; charset = fts_index_get_charset(index); @@ -3828,15 +3836,17 @@ fts_query( query.fts_index_table.table_id = index->table->id; query.fts_index_table.parent = index->table->name; query.fts_index_table.charset = charset; + query.fts_index_table.table = index->table; - query.word_map = new word_map_t; + query.word_map = rbt_create_arg_cmp( + sizeof(fts_string_t), innobase_fts_text_cmp, (void*) charset); query.word_vector = new word_vector_t; query.error = DB_SUCCESS; /* Setup the RB tree that will be used to collect per term statistics. */ query.word_freqs = rbt_create_arg_cmp( - sizeof(fts_word_freq_t), innobase_fts_string_cmp, (void*) charset); + sizeof(fts_word_freq_t), innobase_fts_text_cmp, (void*) charset); query.total_size += SIZEOF_RBT_CREATE; @@ -4060,13 +4070,14 @@ fts_print_doc_id( fts_ranking_t* ranking; ranking = rbt_value(fts_ranking_t, node); - fprintf(stderr, "doc_ids info, doc_id: %ld \n", + ib_logf(IB_LOG_LEVEL_INFO, "doc_ids info, doc_id: %ld \n", (ulint) ranking->doc_id); - ulint pos = 0; - byte* value = NULL; - while (fts_ranking_words_get_next(query, ranking, &pos, &value)) { - fprintf(stderr, "doc_ids info, value: %s \n", value); + ulint pos = 0; + fts_string_t word; + + while (fts_ranking_words_get_next(query, ranking, &pos, &word)) { + ib_logf(IB_LOG_LEVEL_INFO, "doc_ids info, value: %s \n", word.f_str); } } } @@ -4122,7 +4133,7 @@ fts_expand_query( fts_ranking_t* ranking; ulint pos; - byte* word; + fts_string_t word; ulint prev_token_size; ulint estimate_size; @@ -4144,22 +4155,17 @@ fts_expand_query( /* Remove words that have already been searched in the first pass */ pos = 0; - word = NULL; while (fts_ranking_words_get_next(query, ranking, &pos, - &word)) { - fts_string_t str; + &word)) { ibool ret; - /* FIXME: We are discarding a const qualifier here. */ - str.f_str = word; - str.f_len = ut_strlen((const char*) str.f_str); - ret = rbt_delete(result_doc.tokens, &str); + ret = rbt_delete(result_doc.tokens, &word); /* The word must exist in the doc we found */ if (!ret) { - fprintf(stderr, " InnoDB: Error: Did not " + ib_logf(IB_LOG_LEVEL_ERROR, "Did not " "find word %s in doc %ld for query " - "expansion search.\n", str.f_str, + "expansion search.\n", word.f_str, (ulint) ranking->doc_id); } } @@ -4184,7 +4190,8 @@ fts_expand_query( fts_token_t* mytoken; mytoken = rbt_value(fts_token_t, token_node); - fts_query_add_word_freq(query, mytoken->text.f_str); + ut_ad(mytoken->text.f_str[mytoken->text.f_len] == 0); + fts_query_add_word_freq(query, &mytoken->text); error = fts_query_union(query, &mytoken->text); if (error != DB_SUCCESS) { @@ -4323,8 +4330,7 @@ fts_phrase_or_proximity_search( token = static_cast( ib_vector_get(tokens, z)); fts_query_add_word_to_document( - query, match[0]->doc_id, - token->f_str); + query, match[0]->doc_id, token); } } } diff --git a/storage/xtradb/fts/fts0sql.cc b/storage/xtradb/fts/fts0sql.cc index 03c19d93af6..14bc3ec44c9 100644 --- a/storage/xtradb/fts/fts0sql.cc +++ b/storage/xtradb/fts/fts0sql.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2013, 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 @@ -61,21 +61,28 @@ fts_get_table_id( long */ { int len; + bool hex_name = DICT_TF2_FLAG_IS_SET(fts_table->table, + DICT_TF2_FTS_AUX_HEX_NAME); + + ut_a(fts_table->table != NULL); switch (fts_table->type) { case FTS_COMMON_TABLE: - len = fts_write_object_id(fts_table->table_id, table_id); + len = fts_write_object_id(fts_table->table_id, table_id, + hex_name); break; case FTS_INDEX_TABLE: - len = fts_write_object_id(fts_table->table_id, table_id); + len = fts_write_object_id(fts_table->table_id, table_id, + hex_name); table_id[len] = '_'; ++len; table_id += len; - len += fts_write_object_id(fts_table->index_id, table_id); + len += fts_write_object_id(fts_table->index_id, table_id, + hex_name); break; default: @@ -191,7 +198,7 @@ fts_parse_sql( str = ut_str3cat(fts_sql_begin, str_tmp, fts_sql_end); mem_free(str_tmp); - dict_locked = (fts_table && fts_table->table + dict_locked = (fts_table && fts_table->table->fts && (fts_table->table->fts->fts_status & TABLE_DICT_LOCKED)); diff --git a/storage/xtradb/fts/fts0tlex.cc b/storage/xtradb/fts/fts0tlex.cc index 717ddb8a77e..f78456d8795 100644 --- a/storage/xtradb/fts/fts0tlex.cc +++ b/storage/xtradb/fts/fts0tlex.cc @@ -305,9 +305,9 @@ YY_BUFFER_STATE fts0t_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner YY_BUFFER_STATE fts0t_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); YY_BUFFER_STATE fts0t_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); -void *fts0talloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); -void *fts0trealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); -void fts0tfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +void *fts0talloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +void *fts0trealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +void fts0tfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); #define yy_new_buffer fts0t_create_buffer @@ -347,7 +347,7 @@ typedef int yy_state_type; static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); static int yy_get_next_buffer (yyscan_t yyscanner ); -static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); +static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. @@ -575,11 +575,11 @@ extern int fts0twrap (yyscan_t yyscanner ); #endif #ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); +static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); +static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))); #endif #ifndef YY_NO_INPUT @@ -1601,7 +1601,7 @@ YY_BUFFER_STATE fts0t_scan_bytes (yyconst char * yybytes, int _yybytes_len , y #define YY_EXIT_FAILURE 2 #endif -static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); @@ -1902,7 +1902,7 @@ int fts0tlex_destroy (yyscan_t yyscanner) */ #ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { register int i; for ( i = 0; i < n; ++i ) @@ -1911,7 +1911,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { register int n; for ( n = 0; s[n]; ++n ) @@ -1921,12 +1921,12 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribu } #endif -void *fts0talloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +void *fts0talloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { return (void *) malloc( size ); } -void *fts0trealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +void *fts0trealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those @@ -1938,7 +1938,7 @@ void *fts0trealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __at return (void *) realloc( (char *) ptr, size ); } -void fts0tfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) +void fts0tfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused))) { free( (char *) ptr ); /* see fts0trealloc() for (char *) cast */ } diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 9ee93937bb5..1c3bccf8302 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -469,6 +469,7 @@ static PSI_thread_info all_innodb_threads[] = { {&srv_master_thread_key, "srv_master_thread", 0}, {&srv_purge_thread_key, "srv_purge_thread", 0}, {&buf_page_cleaner_thread_key, "page_cleaner_thread", 0}, + {&buf_lru_manager_thread_key, "lru_manager_thread", 0}, {&recv_writer_thread_key, "recv_writer_thread", 0}, {&srv_log_tracking_thread_key, "srv_redo_log_follow_thread", 0} }; @@ -547,6 +548,7 @@ ib_cb_t innodb_api_cb[] = { (ib_cb_t) ib_cursor_open_index_using_name, (ib_cb_t) ib_close_thd, (ib_cb_t) ib_cfg_get_cfg, + (ib_cb_t) ib_cursor_set_memcached_sync, (ib_cb_t) ib_cursor_set_cluster_access, (ib_cb_t) ib_cursor_commit_trx, (ib_cb_t) ib_cfg_trx_level, @@ -964,6 +966,19 @@ innobase_rollback_to_savepoint( be rolled back to savepoint */ void* savepoint); /*!< in: savepoint data */ +/*****************************************************************//** +Check whether innodb state allows to safely release MDL locks after +rollback to savepoint. +@return true if it is safe, false if its not safe. */ +static +bool +innobase_rollback_to_savepoint_can_release_mdl( +/*===========================================*/ + handlerton* hton, /*!< in/out: InnoDB handlerton */ + THD* thd); /*!< in: handle to the MySQL thread of + the user whose XA transaction should + be rolled back to savepoint */ + /*****************************************************************//** Sets a transaction savepoint. @return always 0, that is, always succeeds */ @@ -3191,6 +3206,8 @@ innobase_init( innobase_hton->close_connection = innobase_close_connection; innobase_hton->savepoint_set = innobase_savepoint; innobase_hton->savepoint_rollback = innobase_rollback_to_savepoint; + innobase_hton->savepoint_rollback_can_release_mdl = + innobase_rollback_to_savepoint_can_release_mdl; innobase_hton->savepoint_release = innobase_release_savepoint; innobase_hton->commit_ordered=innobase_commit_ordered; innobase_hton->commit = innobase_commit; @@ -4462,6 +4479,38 @@ innobase_rollback_to_savepoint( DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL)); } +/*****************************************************************//** +Check whether innodb state allows to safely release MDL locks after +rollback to savepoint. +When binlog is on, MDL locks acquired after savepoint unit are not +released if there are any locks held in InnoDB. +@return true if it is safe, false if its not safe. */ +static +bool +innobase_rollback_to_savepoint_can_release_mdl( +/*===========================================*/ + handlerton* hton, /*!< in: InnoDB handlerton */ + THD* thd) /*!< in: handle to the MySQL thread + of the user whose transaction should + be rolled back to savepoint */ +{ + trx_t* trx; + + DBUG_ENTER("innobase_rollback_to_savepoint_can_release_mdl"); + DBUG_ASSERT(hton == innodb_hton_ptr); + + trx = check_trx_exists(thd); + ut_ad(trx); + + /* If transaction has not acquired any locks then it is safe + to release MDL after rollback to savepoint */ + if (!(UT_LIST_GET_LEN(trx->lock.trx_locks))) { + DBUG_RETURN(true); + } + + DBUG_RETURN(false); +} + /*****************************************************************//** Release transaction savepoint name. @return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the @@ -6148,23 +6197,7 @@ innobase_fts_text_cmp_prefix( to negate the result */ return(-result); } -/******************************************************************//** -compare two character string according to their charset. */ -UNIV_INTERN -int -innobase_fts_string_cmp( -/*====================*/ - const void* cs, /*!< in: Character set */ - const void* p1, /*!< in: key */ - const void* p2) /*!< in: node */ -{ - const CHARSET_INFO* charset = (const CHARSET_INFO*) cs; - uchar* s1 = (uchar*) p1; - uchar* s2 = *(uchar**) p2; - return(ha_compare_text(charset, s1, strlen((const char*) s1), - s2, strlen((const char*) s2), 0, 0)); -} /******************************************************************//** Makes all characters in a string lower case. */ UNIV_INTERN @@ -9238,12 +9271,6 @@ ha_innobase::position( } } -/* limit innodb monitor access to users with PROCESS privilege. -See http://bugs.mysql.com/32710 for expl. why we choose PROCESS. */ -#define IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name, thd) \ - (row_is_magic_monitor_table(table_name) \ - && check_global_access(thd, PROCESS_ACL)) - /*****************************************************************//** Check whether there exist a column named as "FTS_DOC_ID", which is reserved for InnoDB FTS Doc ID @@ -9358,16 +9385,6 @@ create_table_def( DBUG_RETURN(ER_TABLE_NAME); } - /* table_name must contain '/'. Later in the code we assert if it - does not */ - if (strcmp(strchr(table_name, '/') + 1, - "innodb_table_monitor") == 0) { - push_warning( - thd, Sql_condition::WARN_LEVEL_WARN, - HA_ERR_WRONG_COMMAND, - DEPRECATED_MSG_INNODB_TABLE_MONITOR); - } - n_cols = form->s->fields; s_cols = form->s->stored_fields; @@ -9392,18 +9409,18 @@ create_table_def( /* Adjust for the FTS hidden field */ if (!has_doc_id_col) { table = dict_mem_table_create(table_name, 0, s_cols + 1, - flags, flags2); + flags, flags2, false); /* Set the hidden doc_id column. */ table->fts->doc_col = s_cols; } else { table = dict_mem_table_create(table_name, 0, s_cols, - flags, flags2); + flags, flags2, false); table->fts->doc_col = doc_id_col; } } else { table = dict_mem_table_create(table_name, 0, s_cols, - flags, flags2); + flags, flags2, false); } if (flags2 & DICT_TF2_TEMPORARY) { @@ -9741,6 +9758,7 @@ get_row_format_name( return("FIXED"); case ROW_TYPE_PAGE: case ROW_TYPE_NOT_USED: + default: break; } return("NOT USED"); @@ -9886,6 +9904,7 @@ create_options_are_invalid( case ROW_TYPE_FIXED: case ROW_TYPE_PAGE: case ROW_TYPE_NOT_USED: + default: push_warning( thd, Sql_condition::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, \ @@ -10253,6 +10272,7 @@ index_bad: case ROW_TYPE_NOT_USED: case ROW_TYPE_FIXED: case ROW_TYPE_PAGE: + default: push_warning( thd, Sql_condition::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, @@ -10283,6 +10303,11 @@ index_bad: *flags2 |= DICT_TF2_USE_TABLESPACE; } + /* Set the flags2 when create table or alter tables */ + *flags2 |= DICT_TF2_FTS_AUX_HEX_NAME; + DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name", + *flags2 &= ~DICT_TF2_FTS_AUX_HEX_NAME;); + DBUG_RETURN(true); } @@ -10374,8 +10399,23 @@ ha_innobase::create( DBUG_RETURN(-1); } - if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) { - DBUG_RETURN(HA_ERR_GENERIC); + if (row_is_magic_monitor_table(norm_name)) { + push_warning_printf(thd, + Sql_condition::WARN_LEVEL_WARN, + HA_ERR_WRONG_COMMAND, + "Using the table name %s to enable " + "diagnostic output is deprecated " + "and may be removed in future releases. " + "Use INFORMATION_SCHEMA or " + "PERFORMANCE_SCHEMA tables or " + "SET GLOBAL innodb_status_output=ON.", + dict_remove_db_name(norm_name)); + + /* Limit innodb monitor access to users with PROCESS privilege. + See http://bugs.mysql.com/32710 why we chose PROCESS. */ + if (check_global_access(thd, PROCESS_ACL)) { + DBUG_RETURN(HA_ERR_GENERIC); + } } /* Get the transaction associated with the current thd, or create one @@ -10837,7 +10877,8 @@ ha_innobase::delete_table( if (srv_read_only_mode) { DBUG_RETURN(HA_ERR_TABLE_READONLY); - } else if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) { + } else if (row_is_magic_monitor_table(norm_name) + && check_global_access(thd, PROCESS_ACL)) { DBUG_RETURN(HA_ERR_GENERIC); } @@ -11086,17 +11127,7 @@ innobase_rename_table( } } - if (error != DB_SUCCESS) { - if (!srv_read_only_mode) { - FILE* ef = dict_foreign_err_file; - - fputs("InnoDB: Renaming table ", ef); - ut_print_name(ef, trx, TRUE, norm_from); - fputs(" to ", ef); - ut_print_name(ef, trx, TRUE, norm_to); - fputs(" failed!\n", ef); - } - } else { + if (error == DB_SUCCESS) { #ifndef __WIN__ sql_print_warning("Rename partition table %s " "succeeds after converting to lower " @@ -12102,7 +12133,8 @@ ha_innobase::optimize( calls to OPTIMIZE, which is undesirable. */ if (innodb_optimize_fulltext_only) { - if (prebuilt->table->fts && prebuilt->table->fts->cache) { + if (prebuilt->table->fts && prebuilt->table->fts->cache + && !dict_table_is_discarded(prebuilt->table)) { fts_sync_table(prebuilt->table); fts_optimize_table(prebuilt->table); } @@ -16106,7 +16138,7 @@ innodb_enable_monitor_at_startup( /****************************************************************//** Update the innodb_sched_priority_cleaner variable and set the thread -priority accordingly. */ +priorities accordingly. */ static void innodb_sched_priority_cleaner_update( @@ -16122,6 +16154,24 @@ innodb_sched_priority_cleaner_update( ulint priority = *static_cast(save); ulint actual_priority; + /* Set the priority for the LRU manager thread */ + ut_ad(buf_lru_manager_is_active); + actual_priority = os_thread_set_priority(srv_lru_manager_tid, + priority); + if (UNIV_UNLIKELY(actual_priority != priority)) { + + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_WRONG_ARGUMENTS, + "Failed to set the LRU manager thread " + "priority to %lu, " + "the current priority is %lu", priority, + actual_priority); + } else { + + srv_sched_priority_cleaner = priority; + } + + /* Set the priority for the page cleaner thread */ if (srv_read_only_mode) { return; @@ -16137,9 +16187,6 @@ innodb_sched_priority_cleaner_update( "priority to %lu, " "the current priority is %lu", priority, actual_priority); - } else { - - srv_sched_priority_cleaner = priority; } } @@ -16444,6 +16491,7 @@ innobase_fts_find_ranking( static my_bool innodb_purge_run_now = TRUE; static my_bool innodb_purge_stop_now = TRUE; static my_bool innodb_log_checkpoint_now = TRUE; +static my_bool innodb_buf_flush_list_now = TRUE; static my_bool innodb_track_redo_log_now = TRUE; /****************************************************************//** @@ -16519,6 +16567,29 @@ checkpoint_now_set( } } +/****************************************************************//** +Force a dirty pages flush now. */ +static +void +buf_flush_list_now_set( +/*===================*/ + THD* thd /*!< in: thread handle */ + __attribute__((unused)), + struct st_mysql_sys_var* var /*!< in: pointer to system + variable */ + __attribute__((unused)), + void* var_ptr /*!< out: where the formal + string goes */ + __attribute__((unused)), + const void* save) /*!< in: immediate result from + check function */ +{ + if (*(my_bool*) save) { + buf_flush_list(ULINT_MAX, LSN_MAX, NULL); + buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); + } +} + /****************************************************************//** Force log tracker to track the log synchronously. */ static @@ -16526,13 +16597,13 @@ void track_redo_log_now_set( /*===================*/ THD* thd /*!< in: thread handle */ - __attribute__((unused)), + __attribute__((unused)), struct st_mysql_sys_var* var /*!< in: pointer to system variable */ - __attribute__((unused)), + __attribute__((unused)), void* var_ptr /*!< out: where the formal string goes */ - __attribute__((unused)), + __attribute__((unused)), const void* save) /*!< in: immediate result from check function */ { @@ -16542,7 +16613,6 @@ track_redo_log_now_set( } } - #endif /* UNIV_DEBUG */ /*********************************************************************** @@ -16703,6 +16773,26 @@ buffer_pool_load_abort( } } +/** Update innodb_status_output or innodb_status_output_locks, +which control InnoDB "status monitor" output to the error log. +@param[in] thd thread handle +@param[in] var system variable +@param[out] var_ptr current value +@param[in] save to-be-assigned value */ +static +void +innodb_status_output_update( + THD* thd __attribute__((unused)), + struct st_mysql_sys_var* var __attribute__((unused)), + void* var_ptr __attribute__((unused)), + const void* save __attribute__((unused))) +{ + *static_cast(var_ptr) = *static_cast(save); + /* The lock timeout monitor thread also takes care of this + output. */ + os_event_set(lock_sys->timeout_event); +} + static SHOW_VAR innodb_status_variables_export[]= { {"Innodb", (char*) &show_innodb_vars, SHOW_FUNC}, {NullS, NullS, SHOW_LONG} @@ -16831,11 +16921,17 @@ static MYSQL_SYSVAR_BOOL(log_checkpoint_now, innodb_log_checkpoint_now, "Force checkpoint now", NULL, checkpoint_now_set, FALSE); +static MYSQL_SYSVAR_BOOL(buf_flush_list_now, innodb_buf_flush_list_now, + PLUGIN_VAR_OPCMDARG, + "Force dirty page flush now", + NULL, buf_flush_list_now_set, FALSE); + static MYSQL_SYSVAR_BOOL(track_redo_log_now, innodb_track_redo_log_now, PLUGIN_VAR_OPCMDARG, "Force log tracker to catch up with checkpoint now", NULL, track_redo_log_now_set, FALSE); + #endif /* UNIV_DEBUG */ static MYSQL_SYSVAR_ULONG(purge_batch_size, srv_purge_batch_size, @@ -17138,7 +17234,7 @@ static MYSQL_SYSVAR_ENUM(foreground_preflush, srv_foreground_preflush, static MYSQL_SYSVAR_ULONG(sched_priority_cleaner, srv_sched_priority_cleaner, PLUGIN_VAR_RQCMDARG, - "Nice value for the cleaner thread scheduling", + "Nice value for the cleaner and LRU manager thread scheduling", NULL, innodb_sched_priority_cleaner_update, 19, 0, 39, 0); #endif /* UNIV_LINUX */ @@ -17183,7 +17279,8 @@ static MYSQL_SYSVAR_BOOL(priority_io, srv_io_thread_priority, static MYSQL_SYSVAR_BOOL(priority_cleaner, srv_cleaner_thread_priority, PLUGIN_VAR_OPCMDARG, - "Make buffer pool cleaner thread acquire shared resources with priority", + "Make buffer pool cleaner and LRU manager threads acquire shared resources " + "with priority", NULL, NULL, FALSE); static MYSQL_SYSVAR_BOOL(priority_master, srv_master_thread_priority, @@ -17685,6 +17782,15 @@ static MYSQL_SYSVAR_STR(monitor_reset_all, innobase_reset_all_monitor_counter, innodb_monitor_validate, innodb_reset_all_monitor_update, NULL); +static MYSQL_SYSVAR_BOOL(status_output, srv_print_innodb_monitor, + PLUGIN_VAR_OPCMDARG, "Enable InnoDB monitor output to the error log.", + NULL, innodb_status_output_update, FALSE); + +static MYSQL_SYSVAR_BOOL(status_output_locks, srv_print_innodb_lock_monitor, + PLUGIN_VAR_OPCMDARG, "Enable InnoDB lock monitor output to the error log." + " Requires innodb_status_output=ON.", + NULL, innodb_status_output_update, FALSE); + static MYSQL_SYSVAR_BOOL(print_all_deadlocks, srv_print_all_deadlocks, PLUGIN_VAR_OPCMDARG, "Print all deadlocks to MySQL error log (off by default)", @@ -17916,6 +18022,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(purge_run_now), MYSQL_SYSVAR(purge_stop_now), MYSQL_SYSVAR(log_checkpoint_now), + MYSQL_SYSVAR(buf_flush_list_now), MYSQL_SYSVAR(track_redo_log_now), #endif /* UNIV_DEBUG */ #ifdef UNIV_LINUX @@ -17940,6 +18047,8 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(cleaner_free_list_lwm), MYSQL_SYSVAR(cleaner_eviction_factor), #endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */ + MYSQL_SYSVAR(status_output), + MYSQL_SYSVAR(status_output_locks), MYSQL_SYSVAR(cleaner_lsn_age_factor), MYSQL_SYSVAR(foreground_preflush), MYSQL_SYSVAR(empty_free_list_algorithm), @@ -18302,7 +18411,9 @@ ib_errf( str[size - 1] = 0x0; vsnprintf(str, size, format, args); #elif HAVE_VASPRINTF - (void) vasprintf(&str, format, args); + int ret; + ret = vasprintf(&str, format, args); + ut_a(ret != -1); #else /* Use a fixed length string. */ str = static_cast(malloc(BUFSIZ)); @@ -18336,7 +18447,9 @@ ib_logf( str[size - 1] = 0x0; vsnprintf(str, size, format, args); #elif HAVE_VASPRINTF - (void) vasprintf(&str, format, args); + int ret; + ret = vasprintf(&str, format, args); + ut_a(ret != -1); #else /* Use a fixed length string. */ str = static_cast(malloc(BUFSIZ)); diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc index 21859cb5447..13c6752ce8f 100644 --- a/storage/xtradb/handler/handler0alter.cc +++ b/storage/xtradb/handler/handler0alter.cc @@ -46,7 +46,7 @@ Smart ALTER TABLE #include "srv0mon.h" #include "fts0priv.h" #include "pars0pars.h" - +#include "row0sel.h" #include "ha_innodb.h" /** Operations for creating secondary indexes (no rebuild needed) */ @@ -240,6 +240,7 @@ ha_innobase::check_if_supported_inplace_alter( innobase_get_err_msg(ER_READ_ONLY_MODE); DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } else if (srv_created_new_raw || srv_force_recovery) { + ha_alter_info->unsupported_reason = innobase_get_err_msg(ER_READ_ONLY_MODE); DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); @@ -2532,15 +2533,16 @@ innobase_drop_fts_index_table( /** Get the new column names if any columns were renamed @param ha_alter_info Data used during in-place alter @param altered_table MySQL table that is being altered +@param table MySQL table as it is before the ALTER operation @param user_table InnoDB table as it is before the ALTER operation @param heap Memory heap for the allocation @return array of new column names in rebuilt_table, or NULL if not renamed */ static __attribute__((nonnull, warn_unused_result)) const char** innobase_get_col_names( -/*===================*/ Alter_inplace_info* ha_alter_info, const TABLE* altered_table, + const TABLE* table, const dict_table_t* user_table, mem_heap_t* heap) { @@ -2548,19 +2550,31 @@ innobase_get_col_names( uint i; DBUG_ENTER("innobase_get_col_names"); - DBUG_ASSERT(user_table->n_def > altered_table->s->fields); + DBUG_ASSERT(user_table->n_def > table->s->fields); DBUG_ASSERT(ha_alter_info->handler_flags & Alter_inplace_info::ALTER_COLUMN_NAME); cols = static_cast( - mem_heap_alloc(heap, user_table->n_def * sizeof *cols)); + mem_heap_zalloc(heap, user_table->n_def * sizeof *cols)); - for (i = 0; i < altered_table->s->fields; i++) { - const Field* field = altered_table->field[i]; - cols[i] = field->field_name; + i = 0; + List_iterator_fast cf_it( + ha_alter_info->alter_info->create_list); + while (const Create_field* new_field = cf_it++) { + DBUG_ASSERT(i < altered_table->s->fields); + + for (uint old_i = 0; table->field[old_i]; old_i++) { + if (new_field->field == table->field[old_i]) { + cols[old_i] = new_field->field_name; + break; + } + } + + i++; } /* Copy the internal column names. */ + i = table->s->fields; cols[i] = dict_table_get_col_name(user_table, i); while (++i < user_table->n_def) { @@ -2776,7 +2790,7 @@ prepare_inplace_alter_table_dict( /* The initial space id 0 may be overridden later. */ ctx->new_table = dict_mem_table_create( - new_table_name, 0, n_cols, flags, flags2); + new_table_name, 0, n_cols, flags, flags2, false); /* The rebuilt indexed_table will use the renamed column names. */ ctx->col_names = NULL; @@ -3346,6 +3360,9 @@ ha_innobase::prepare_inplace_alter_table( ulint fts_doc_col_no = ULINT_UNDEFINED; bool add_fts_doc_id = false; bool add_fts_doc_id_idx = false; +#ifdef _WIN32 + bool add_fts_idx = false; +#endif /* _WIN32 */ DBUG_ENTER("prepare_inplace_alter_table"); DBUG_ASSERT(!ha_alter_info->handler_ctx); @@ -3494,6 +3511,9 @@ check_if_ok_to_rename: & ~(HA_FULLTEXT | HA_PACK_KEY | HA_BINARY_PACK_KEY))); +#ifdef _WIN32 + add_fts_idx = true; +#endif /* _WIN32 */ continue; } @@ -3504,6 +3524,20 @@ check_if_ok_to_rename: } } +#ifdef _WIN32 + /* We won't be allowed to add fts index to a table with + fts indexes already but without AUX_HEX_NAME set. + This means the aux tables of the table failed to + rename to hex format but new created aux tables + shall be in hex format, which is contradictory. + It's only for Windows. */ + if (!DICT_TF2_FLAG_IS_SET(indexed_table, DICT_TF2_FTS_AUX_HEX_NAME) + && indexed_table->fts != NULL && add_fts_idx) { + my_error(ER_INNODB_FT_AUX_NOT_HEX_ID, MYF(0)); + goto err_exit_no_heap; + } +#endif /* _WIN32 */ + /* Check existing index definitions for too-long column prefixes as well, in case max_col_len shrunk. */ for (const dict_index_t* index @@ -3537,8 +3571,8 @@ check_if_ok_to_rename: if (ha_alter_info->handler_flags & Alter_inplace_info::ALTER_COLUMN_NAME) { col_names = innobase_get_col_names( - ha_alter_info, altered_table, indexed_table, - heap); + ha_alter_info, altered_table, table, + indexed_table, heap); } else { col_names = NULL; } @@ -4608,16 +4642,39 @@ commit_get_autoinc( & Alter_inplace_info::CHANGE_CREATE_OPTION) && (ha_alter_info->create_info->used_fields & HA_CREATE_USED_AUTO)) { - /* An AUTO_INCREMENT value was supplied, but the table - was not rebuilt. Get the user-supplied value or the - last value from the sequence. */ - ut_ad(old_table->found_next_number_field); + /* An AUTO_INCREMENT value was supplied, but the table was not + rebuilt. Get the user-supplied value or the last value from the + sequence. */ + ib_uint64_t max_value_table; + dberr_t err; + + Field* autoinc_field = + old_table->found_next_number_field; + + dict_index_t* index = dict_table_get_index_on_first_col( + ctx->old_table, autoinc_field->field_index); max_autoinc = ha_alter_info->create_info->auto_increment_value; dict_table_autoinc_lock(ctx->old_table); - if (max_autoinc < ctx->old_table->autoinc) { - max_autoinc = ctx->old_table->autoinc; + + err = row_search_max_autoinc( + index, autoinc_field->field_name, &max_value_table); + + if (err != DB_SUCCESS) { + ut_ad(0); + max_autoinc = 0; + } else if (max_autoinc <= max_value_table) { + ulonglong col_max_value; + ulonglong offset; + + col_max_value = innobase_get_int_col_max_value( + old_table->found_next_number_field); + + offset = ctx->prebuilt->autoinc_offset; + max_autoinc = innobase_next_autoinc( + max_value_table, 1, 1, offset, + col_max_value); } dict_table_autoinc_unlock(ctx->old_table); } else { diff --git a/storage/xtradb/ibuf/ibuf0ibuf.cc b/storage/xtradb/ibuf/ibuf0ibuf.cc index 2964fa99c8a..7e5d5532ee3 100644 --- a/storage/xtradb/ibuf/ibuf0ibuf.cc +++ b/storage/xtradb/ibuf/ibuf0ibuf.cc @@ -611,7 +611,8 @@ ibuf_init_at_db_start(void) heap = mem_heap_create(450); /* Use old-style record format for the insert buffer. */ - table = dict_mem_table_create(IBUF_TABLE_NAME, IBUF_SPACE_ID, 1, 0, 0); + table = dict_mem_table_create(IBUF_TABLE_NAME, IBUF_SPACE_ID, 1, 0, 0, + false); dict_mem_table_add_col(table, heap, "DUMMY_COLUMN", DATA_BINARY, 0, 0); @@ -1572,7 +1573,7 @@ ibuf_dummy_index_create( table = dict_mem_table_create("IBUF_DUMMY", DICT_HDR_SPACE, n, - comp ? DICT_TF_COMPACT : 0, 0); + comp ? DICT_TF_COMPACT : 0, 0, true); index = dict_mem_index_create("IBUF_DUMMY", "IBUF_DUMMY", DICT_HDR_SPACE, 0, n); diff --git a/storage/xtradb/include/api0api.h b/storage/xtradb/include/api0api.h index c294e3f34d5..d77d691becc 100644 --- a/storage/xtradb/include/api0api.h +++ b/storage/xtradb/include/api0api.h @@ -1256,6 +1256,16 @@ int ib_cfg_get_cfg(); /*============*/ +/*****************************************************************//** +Increase/decrease the memcached sync count of table to sync memcached +DML with SQL DDLs. +@return DB_SUCCESS or error number */ +ib_err_t +ib_cursor_set_memcached_sync( +/*=========================*/ + ib_crsr_t ib_crsr, /*!< in: cursor */ + ib_bool_t flag); /*!< in: true for increasing */ + /*****************************************************************//** Check whether the table name conforms to our requirements. Currently we only do a simple check for the presence of a '/'. diff --git a/storage/xtradb/include/btr0pcur.h b/storage/xtradb/include/btr0pcur.h index fc008cdd185..cfbaacf4de3 100644 --- a/storage/xtradb/include/btr0pcur.h +++ b/storage/xtradb/include/btr0pcur.h @@ -459,6 +459,13 @@ void btr_pcur_move_to_prev_on_page( /*==========================*/ btr_pcur_t* cursor);/*!< in/out: persistent cursor */ +/*********************************************************//** +Moves the persistent cursor to the infimum record on the same page. */ +UNIV_INLINE +void +btr_pcur_move_before_first_on_page( +/*===============================*/ + btr_pcur_t* cursor); /*!< in/out: persistent cursor */ /** Position state of persistent B-tree cursor. */ enum pcur_pos_t { diff --git a/storage/xtradb/include/btr0pcur.ic b/storage/xtradb/include/btr0pcur.ic index 29f2fc722a2..7e355d3709d 100644 --- a/storage/xtradb/include/btr0pcur.ic +++ b/storage/xtradb/include/btr0pcur.ic @@ -588,3 +588,19 @@ btr_pcur_close( cursor->trx_if_known = NULL; } + +/*********************************************************//** +Moves the persistent cursor to the infimum record on the same page. */ +UNIV_INLINE +void +btr_pcur_move_before_first_on_page( +/*===============================*/ + btr_pcur_t* cursor) /*!< in/out: persistent cursor */ +{ + ut_ad(cursor->latch_mode != BTR_NO_LATCHES); + + page_cur_set_before_first(btr_pcur_get_block(cursor), + btr_pcur_get_page_cur(cursor)); + + cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; +} diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h index ba2f413429c..8e2c283476a 100644 --- a/storage/xtradb/include/buf0buf.h +++ b/storage/xtradb/include/buf0buf.h @@ -596,6 +596,23 @@ buf_block_buf_fix_inc_func( # endif /* UNIV_SYNC_DEBUG */ buf_block_t* block) /*!< in/out: block to bufferfix */ __attribute__((nonnull)); + +/*******************************************************************//** +Increments the bufferfix count. */ +UNIV_INLINE +void +buf_block_fix( +/*===========*/ + buf_block_t* block); /*!< in/out: block to bufferfix */ + +/*******************************************************************//** +Increments the bufferfix count. */ +UNIV_INLINE +void +buf_block_unfix( +/*===========*/ + buf_block_t* block); /*!< in/out: block to bufferfix */ + # ifdef UNIV_SYNC_DEBUG /** Increments the bufferfix count. @param b in/out: block to bufferfix @@ -1437,25 +1454,39 @@ struct buf_page_t{ machine word. */ /* @{ */ - unsigned space:32; /*!< tablespace id. */ - unsigned offset:32; /*!< page number. */ + ib_uint32_t space; /*!< tablespace id. */ + ib_uint32_t offset; /*!< page number. */ + /** count of how manyfold this block is currently bufferfixed */ +#ifdef PAGE_ATOMIC_REF_COUNT + ib_uint32_t buf_fix_count; + /** type of pending I/O operation; Transitions from BUF_IO_NONE to + BUF_IO_WRITE and back are protected by the buf_page_get_mutex() mutex + and the corresponding flush state mutex. The flush state mutex + protection for io_fix and flush_type is not strictly required, but it + ensures consistent buffer pool instance state snapshots in + buf_pool_validate_instance(). @see enum buf_io_fix */ + byte io_fix; + + byte state; +#else + unsigned buf_fix_count:19; + + /** type of pending I/O operation; also protected by + buf_pool->mutex for writes only @see enum buf_io_fix */ + unsigned io_fix:2; + + /*!< state of the control block. + State transitions from BUF_BLOCK_READY_FOR_USE to BUF_BLOCK_MEMORY + need not be protected by buf_page_get_mutex(). @see enum buf_page_state. + State changes that are relevant to page_hash are additionally protected + by the appropriate page_hash mutex i.e.: if a page is in page_hash or + is being added to/removed from page_hash then the corresponding changes + must also be protected by page_hash mutex. */ unsigned state:BUF_PAGE_STATE_BITS; - /*!< state of the control block. - State transitions from - BUF_BLOCK_READY_FOR_USE to - BUF_BLOCK_MEMORY need not be - protected by buf_page_get_mutex(). - @see enum buf_page_state. - State changes that are relevant - to page_hash are additionally - protected by the appropriate - page_hash mutex i.e.: if a page - is in page_hash or is being - added to/removed from page_hash - then the corresponding changes - must also be protected by - page_hash mutex. */ + +#endif /* PAGE_ATOMIC_REF_COUNT */ + #ifndef UNIV_HOTBACKUP unsigned flush_type:2; /*!< if this block is currently being flushed to disk, this tells the @@ -1464,18 +1495,6 @@ struct buf_page_t{ mutex and the corresponding flush state mutex. @see buf_flush_t */ - unsigned io_fix:2; /*!< type of pending I/O operation. - Transitions from BUF_IO_NONE to - BUF_IO_WRITE and back are protected by - the buf_page_get_mutex() mutex and the - corresponding flush state mutex. The - flush state mutex protection for io_fix - and flush_type is not strictly - required, but it ensures consistent - buffer pool instance state snapshots in - buf_pool_validate_instance(). */ - unsigned buf_fix_count:19;/*!< count of how manyfold this block - is currently bufferfixed */ unsigned buf_pool_index:6;/*!< index number of the buffer pool that this block belongs to */ # if MAX_BUFFER_POOLS > 64 @@ -1630,7 +1649,7 @@ struct buf_block_t{ decompressed LRU list; used in debugging */ #endif /* UNIV_DEBUG */ - ib_mutex_t mutex; /*!< mutex protecting this block: + ib_mutex_t mutex; /*!< mutex protecting this block: state, io_fix, buf_fix_count, and accessed; we introduce this new mutex in InnoDB-5.1 to relieve @@ -1816,7 +1835,7 @@ struct buf_pool_t{ /** @name General fields */ /* @{ */ - ib_mutex_t zip_mutex; /*!< Zip mutex of this buffer + ib_mutex_t zip_mutex; /*!< Zip mutex of this buffer pool instance, protects compressed only pages (of type buf_page_t, not buf_block_t */ @@ -1873,7 +1892,7 @@ struct buf_pool_t{ /* @{ */ - ib_mutex_t flush_list_mutex;/*!< mutex protecting the + ib_mutex_t flush_list_mutex;/*!< mutex protecting the flush list access. This mutex protects flush_list, flush_rbt and bpage::list pointers when @@ -1994,18 +2013,30 @@ Use these instead of accessing buffer pool mutexes directly. */ #define buf_flush_list_mutex_own(b) mutex_own(&b->flush_list_mutex) /** Acquire the flush list mutex. */ -#define buf_flush_list_mutex_enter(b) do { \ - mutex_enter(&b->flush_list_mutex); \ +#define buf_flush_list_mutex_enter(b) do { \ + mutex_enter(&b->flush_list_mutex); \ } while (0) /** Release the flush list mutex. */ -# define buf_flush_list_mutex_exit(b) do { \ - mutex_exit(&b->flush_list_mutex); \ +# define buf_flush_list_mutex_exit(b) do { \ + mutex_exit(&b->flush_list_mutex); \ } while (0) +/** Test if block->mutex is owned. */ +#define buf_block_mutex_own(b) mutex_own(&(b)->mutex) + +/** Acquire the block->mutex. */ +#define buf_block_mutex_enter(b) do { \ + mutex_enter(&(b)->mutex); \ +} while (0) + +/** Release the trx->mutex. */ +#define buf_block_mutex_exit(b) do { \ + mutex_exit(&(b)->mutex); \ +} while (0) /** Get appropriate page_hash_lock. */ -# define buf_page_hash_lock_get(b, f) \ +# define buf_page_hash_lock_get(b, f) \ hash_get_lock(b->page_hash, f) #ifdef UNIV_SYNC_DEBUG diff --git a/storage/xtradb/include/buf0buf.ic b/storage/xtradb/include/buf0buf.ic index 4ef354b11ab..fa366fd2a56 100644 --- a/storage/xtradb/include/buf0buf.ic +++ b/storage/xtradb/include/buf0buf.ic @@ -345,15 +345,16 @@ buf_page_get_mutex( /*===============*/ const buf_page_t* bpage) /*!< in: pointer to control block */ { - buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); - switch (buf_page_get_state(bpage)) { case BUF_BLOCK_POOL_WATCH: ut_error; return(NULL); case BUF_BLOCK_ZIP_PAGE: - case BUF_BLOCK_ZIP_DIRTY: + case BUF_BLOCK_ZIP_DIRTY: { + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + return(&buf_pool->zip_mutex); + } default: return(&((buf_block_t*) bpage)->mutex); } @@ -641,9 +642,10 @@ buf_page_set_accessed( buf_page_t* bpage) /*!< in/out: control block */ { ut_ad(mutex_own(buf_page_get_mutex(bpage))); + ut_a(buf_page_in_file(bpage)); - if (!bpage->access_time) { + if (bpage->access_time == 0) { /* Make this the time of the first access. */ bpage->access_time = ut_time_ms(); } @@ -1010,6 +1012,26 @@ buf_block_get_modify_clock( return(block->modify_clock); } +/*******************************************************************//** +Increments the bufferfix count. */ +UNIV_INLINE +void +buf_block_fix( +/*===========*/ + buf_block_t* block) /*!< in/out: block to bufferfix */ +{ + ut_ad(!mutex_own(buf_page_get_mutex(&block->page))); +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_increment_uint32(&block->page.buf_fix_count, 1); +#else + ib_mutex_t* block_mutex = buf_page_get_mutex(&block->page); + + mutex_enter(block_mutex); + ++block->page.buf_fix_count; + mutex_exit(block_mutex); +#endif /* PAGE_ATOMIC_REF_COUNT */ +} + /*******************************************************************//** Increments the bufferfix count. */ UNIV_INLINE @@ -1028,9 +1050,36 @@ buf_block_buf_fix_inc_func( ret = rw_lock_s_lock_nowait(&(block->debug_latch), file, line); ut_a(ret); #endif /* UNIV_SYNC_DEBUG */ + +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_increment_uint32(&block->page.buf_fix_count, 1); +#else ut_ad(mutex_own(&block->mutex)); - block->page.buf_fix_count++; + ++block->page.buf_fix_count; +#endif /* PAGE_ATOMIC_REF_COUNT */ +} + +/*******************************************************************//** +Decrements the bufferfix count. */ +UNIV_INLINE +void +buf_block_unfix( +/*============*/ + buf_block_t* block) /*!< in/out: block to bufferunfix */ +{ + ut_ad(block->page.buf_fix_count > 0); + ut_ad(!mutex_own(buf_page_get_mutex(&block->page))); + +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_decrement_uint32(&block->page.buf_fix_count, 1); +#else + ib_mutex_t* block_mutex = buf_page_get_mutex(&block->page); + + mutex_enter(block_mutex); + --block->page.buf_fix_count; + mutex_exit(block_mutex); +#endif /* PAGE_ATOMIC_REF_COUNT */ } /*******************************************************************//** @@ -1041,9 +1090,16 @@ buf_block_buf_fix_dec( /*==================*/ buf_block_t* block) /*!< in/out: block to bufferunfix */ { - ut_ad(mutex_own(&block->mutex)); + ut_ad(block->page.buf_fix_count > 0); + +#ifdef PAGE_ATOMIC_REF_COUNT + os_atomic_decrement_uint32(&block->page.buf_fix_count, 1); +#else + mutex_enter(&block->mutex); + --block->page.buf_fix_count; + mutex_exit(&block->mutex); +#endif /* PAGE_ATOMIC_REF_COUNT */ - block->page.buf_fix_count--; #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&block->debug_latch); #endif @@ -1302,27 +1358,20 @@ buf_page_release_zip( buf_page_t* bpage) /*!< in: buffer block */ { buf_block_t* block; - buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); - ut_ad(bpage); - ut_a(bpage->buf_fix_count > 0); + block = (buf_block_t*) bpage; switch (buf_page_get_state(bpage)) { - case BUF_BLOCK_ZIP_PAGE: - case BUF_BLOCK_ZIP_DIRTY: - mutex_enter(&buf_pool->zip_mutex); - bpage->buf_fix_count--; - mutex_exit(&buf_pool->zip_mutex); - return; case BUF_BLOCK_FILE_PAGE: - block = (buf_block_t*) bpage; - mutex_enter(&block->mutex); #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&block->debug_latch); -#endif - bpage->buf_fix_count--; - mutex_exit(&block->mutex); +#endif /* UNUV_SYNC_DEBUG */ + /* Fall through */ + case BUF_BLOCK_ZIP_PAGE: + case BUF_BLOCK_ZIP_DIRTY: + buf_block_unfix(block); return; + case BUF_BLOCK_POOL_WATCH: case BUF_BLOCK_NOT_USED: case BUF_BLOCK_READY_FOR_USE: @@ -1345,25 +1394,18 @@ buf_page_release( ulint rw_latch) /*!< in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ { - ut_ad(block); - ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); - ut_a(block->page.buf_fix_count > 0); - - mutex_enter(&block->mutex); #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&(block->debug_latch)); #endif - block->page.buf_fix_count--; - - mutex_exit(&block->mutex); - if (rw_latch == RW_S_LATCH) { rw_lock_s_unlock(&(block->lock)); } else if (rw_latch == RW_X_LATCH) { rw_lock_x_unlock(&(block->lock)); } + + buf_block_unfix(block); } #ifdef UNIV_SYNC_DEBUG @@ -1381,6 +1423,7 @@ buf_block_dbg_add_level( { sync_thread_add_level(&block->lock, level, FALSE); } + #endif /* UNIV_SYNC_DEBUG */ /*********************************************************************//** Get the nth chunk's buffer block in the specified buffer pool. diff --git a/storage/xtradb/include/buf0dblwr.h b/storage/xtradb/include/buf0dblwr.h index 1b9336f4002..740286d0a82 100644 --- a/storage/xtradb/include/buf0dblwr.h +++ b/storage/xtradb/include/buf0dblwr.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2013, 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 @@ -29,6 +29,7 @@ Created 2011/12/19 Inaam Rana #include "univ.i" #include "ut0byte.h" #include "log0log.h" +#include "log0recv.h" #ifndef UNIV_HOTBACKUP @@ -44,18 +45,25 @@ UNIV_INTERN void buf_dblwr_create(void); /*==================*/ + /****************************************************************//** At a database startup initializes the doublewrite buffer memory structure if we already have a doublewrite buffer created in the data files. If we are upgrading to an InnoDB version which supports multiple tablespaces, then this function performs the necessary update operations. If we are in a crash -recovery, this function uses a possible doublewrite buffer to restore -half-written pages in the data files. */ +recovery, this function loads the pages from double write buffer into memory. */ UNIV_INTERN void -buf_dblwr_init_or_restore_pages( -/*============================*/ - ibool restore_corrupt_pages); /*!< in: TRUE=restore pages */ +buf_dblwr_init_or_load_pages( +/*=========================*/ + bool load_corrupt_pages); + +/****************************************************************//** +Process the double write buffer pages. */ +void +buf_dblwr_process(void); +/*===================*/ + /****************************************************************//** frees doublewrite buffer. */ UNIV_INTERN diff --git a/storage/xtradb/include/buf0flu.h b/storage/xtradb/include/buf0flu.h index 73525a5bb58..7699e4fda67 100644 --- a/storage/xtradb/include/buf0flu.h +++ b/storage/xtradb/include/buf0flu.h @@ -36,6 +36,9 @@ Created 11/5/1995 Heikki Tuuri /** Flag indicating if the page_cleaner is in active state. */ extern ibool buf_page_cleaner_is_active; +/** Flag indicating if the lru_manager is in active state. */ +extern bool buf_lru_manager_is_active; + /********************************************************************//** Remove a block from the flush list of modified blocks. */ UNIV_INTERN @@ -175,7 +178,7 @@ buf_flush_ready_for_replace( buf_page_in_file(bpage) and in the LRU list */ /******************************************************************//** page_cleaner thread tasked with flushing dirty pages from the buffer -pools. As of now we'll have only one instance of this thread. +pool flush lists. As of now we'll have only one instance of this thread. @return a dummy parameter */ extern "C" UNIV_INTERN os_thread_ret_t @@ -183,6 +186,17 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)( /*==========================================*/ void* arg); /*!< in: a dummy parameter required by os_thread_create */ +/******************************************************************//** +lru_manager thread tasked with performing LRU flushes and evictions to refill +the buffer pool free lists. As of now we'll have only one instance of this +thread. +@return a dummy parameter */ +extern "C" UNIV_INTERN +os_thread_ret_t +DECLARE_THREAD(buf_flush_lru_manager_thread)( +/*=========================================*/ + void* arg); /*!< in: a dummy parameter required by + os_thread_create */ /*********************************************************************//** Clears up tail of the LRU lists: * Put replaceable pages at the tail of LRU to the free list @@ -233,16 +247,18 @@ Writes a flushable page asynchronously from the buffer pool to a file. NOTE: in simulated aio we must call os_aio_simulated_wake_handler_threads after we have posted a batch of writes! NOTE: buf_page_get_mutex(bpage) must be held upon entering this -function, and they will be released by this function. */ +function, and they will be released by this function if it returns true. +LRU_list_mutex must be held iff performing a single page flush and will be +released by the function if it returns true. +@return TRUE if the page was flushed */ UNIV_INTERN -void +bool buf_flush_page( /*===========*/ buf_pool_t* buf_pool, /*!< in: buffer pool instance */ buf_page_t* bpage, /*!< in: buffer control block */ buf_flush_t flush_type, /*!< in: type of flush */ - bool sync) /*!< in: true if sync IO request */ - __attribute__((nonnull)); + bool sync); /*!< in: true if sync IO request */ /********************************************************************//** Returns true if the block is modified and ready for flushing. @return true if can flush immediately */ diff --git a/storage/xtradb/include/buf0types.h b/storage/xtradb/include/buf0types.h index e19eb04a2ce..4eb5ea18cef 100644 --- a/storage/xtradb/include/buf0types.h +++ b/storage/xtradb/include/buf0types.h @@ -26,6 +26,10 @@ Created 11/17/1995 Heikki Tuuri #ifndef buf0types_h #define buf0types_h +#if defined(INNODB_PAGE_ATOMIC_REF_COUNT) && defined(HAVE_ATOMIC_BUILTINS) +#define PAGE_ATOMIC_REF_COUNT +#endif /* INNODB_PAGE_ATOMIC_REF_COUNT && HAVE_ATOMIC_BUILTINS */ + /** Buffer page (uncompressed or compressed) */ struct buf_page_t; /** Buffer block for which an uncompressed page exists */ diff --git a/storage/xtradb/include/dict0dict.h b/storage/xtradb/include/dict0dict.h index 6669f60b95a..3e3fb9f896c 100644 --- a/storage/xtradb/include/dict0dict.h +++ b/storage/xtradb/include/dict0dict.h @@ -1443,20 +1443,16 @@ UNIV_INTERN void dict_table_stats_lock( /*==================*/ - const dict_table_t* table, /*!< in: table */ - ulint latch_mode) /*!< in: RW_S_LATCH or - RW_X_LATCH */ - __attribute__((nonnull)); + dict_table_t* table, /*!< in: table */ + ulint latch_mode); /*!< in: RW_S_LATCH or RW_X_LATCH */ /**********************************************************************//** Unlock the latch that has been locked by dict_table_stats_lock() */ UNIV_INTERN void dict_table_stats_unlock( /*====================*/ - const dict_table_t* table, /*!< in: table */ - ulint latch_mode) /*!< in: RW_S_LATCH or - RW_X_LATCH */ - __attribute__((nonnull)); + dict_table_t* table, /*!< in: table */ + ulint latch_mode); /*!< in: RW_S_LATCH or RW_X_LATCH */ /********************************************************************//** Checks if the database name in two table names is the same. @return TRUE if same db name */ @@ -1802,6 +1798,17 @@ const char* dict_tf_to_row_format_string( /*=========================*/ ulint table_flag); /*!< in: row format setting */ +/*****************************************************************//** +Get index by first field of the index +@return index which is having first field matches +with the field present in field_index position of table */ +UNIV_INLINE +dict_index_t* +dict_table_get_index_on_first_col( +/*==============================*/ + const dict_table_t* table, /*!< in: table */ + ulint col_index); /*!< in: position of column + in table */ #endif /* !UNIV_HOTBACKUP */ /************************************************************************* diff --git a/storage/xtradb/include/dict0dict.ic b/storage/xtradb/include/dict0dict.ic index c261d6a3aee..6bfd7f6cdae 100644 --- a/storage/xtradb/include/dict0dict.ic +++ b/storage/xtradb/include/dict0dict.ic @@ -1403,4 +1403,31 @@ dict_table_is_temporary( return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY)); } +/**********************************************************************//** +Get index by first field of the index +@return index which is having first field matches +with the field present in field_index position of table */ +UNIV_INLINE +dict_index_t* +dict_table_get_index_on_first_col( +/*==============================*/ + const dict_table_t* table, /*!< in: table */ + ulint col_index) /*!< in: position of column + in table */ +{ + ut_ad(col_index < table->n_cols); + + dict_col_t* column = dict_table_get_nth_col(table, col_index); + + for (dict_index_t* index = dict_table_get_first_index(table); + index != NULL; index = dict_table_get_next_index(index)) { + + if (index->fields[0].col == column) { + return(index); + } + } + ut_error; + return(0); +} + #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/xtradb/include/dict0mem.h b/storage/xtradb/include/dict0mem.h index bde0ce16094..527d50019a4 100644 --- a/storage/xtradb/include/dict0mem.h +++ b/storage/xtradb/include/dict0mem.h @@ -198,7 +198,7 @@ ROW_FORMAT=REDUNDANT. InnoDB engines do not check these flags for unknown bits in order to protect backward incompatibility. */ /* @{ */ /** Total number of bits in table->flags2. */ -#define DICT_TF2_BITS 6 +#define DICT_TF2_BITS 7 #define DICT_TF2_BIT_MASK ~(~0 << DICT_TF2_BITS) /** TEMPORARY; TRUE for tables from CREATE TEMPORARY TABLE. */ @@ -216,6 +216,10 @@ use its own tablespace instead of the system tablespace. */ /** Set when we discard/detach the tablespace */ #define DICT_TF2_DISCARDED 32 + +/** This bit is set if all aux table names (both common tables and +index tables) of a FTS table are in HEX format. */ +#define DICT_TF2_FTS_AUX_HEX_NAME 64 /* @} */ #define DICT_TF2_FLAG_SET(table, flag) \ @@ -255,7 +259,10 @@ dict_mem_table_create( of the table is placed */ ulint n_cols, /*!< in: number of columns */ ulint flags, /*!< in: table flags */ - ulint flags2); /*!< in: table flags2 */ + ulint flags2, /*!< in: table flags2 */ + bool nonshared);/*!< in: whether the table object is a dummy + one that does not need the initialization of + locking-related fields. */ /****************************************************************//** Free a table memory object. */ UNIV_INTERN @@ -728,6 +735,11 @@ a foreign key constraint is enforced, therefore RESTRICT just means no flag */ #define DICT_FOREIGN_ON_UPDATE_NO_ACTION 32 /*!< ON UPDATE NO ACTION */ /* @} */ +/* This flag is for sync SQL DDL and memcached DML. +if table->memcached_sync_count == DICT_TABLE_IN_DDL means there's DDL running on +the table, DML from memcached will be blocked. */ +#define DICT_TABLE_IN_DDL -1 + /** Data structure for a database table. Most fields will be initialized to 0, NULL or FALSE in dict_mem_table_create(). */ struct dict_table_t{ @@ -841,9 +853,29 @@ struct dict_table_t{ initialized in dict_table_add_to_cache() */ /** Statistics for query optimization */ /* @{ */ + rw_lock_t* stats_latch; /*!< this latch protects: + dict_table_t::stat_initialized + dict_table_t::stat_n_rows (*) + dict_table_t::stat_clustered_index_size + dict_table_t::stat_sum_of_other_index_sizes + dict_table_t::stat_modified_counter (*) + dict_table_t::indexes*::stat_n_diff_key_vals[] + dict_table_t::indexes*::stat_index_size + dict_table_t::indexes*::stat_n_leaf_pages + (*) those are not always protected for + performance reasons. NULL for dumy table + objects. */ unsigned stat_initialized:1; /*!< TRUE if statistics have been calculated the first time after database startup or table creation */ +#define DICT_TABLE_IN_USED -1 + lint memcached_sync_count; + /*!< count of how many handles are opened + to this table from memcached; DDL on the + table is NOT allowed until this count + goes to zero. If it's -1, means there's DDL + on the table, DML from memcached will be + blocked. */ ib_time_t stats_last_recalc; /*!< Timestamp of last recalc of the stats */ ib_uint32_t stat_persistent; @@ -954,10 +986,12 @@ struct dict_table_t{ and release it without a need to allocate space from the lock heap of the trx: otherwise the lock heap would grow rapidly - if we do a large insert from a select */ + if we do a large insert from a select. NULL + for dummy table objects. */ ib_mutex_t autoinc_mutex; /*!< mutex protecting the autoincrement - counter */ + counter. Not initialized for dummy table + objects */ ib_uint64_t autoinc;/*!< autoinc counter value to give to the next inserted row */ ulong n_waiting_or_granted_auto_inc_locks; diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h index 472c57fcbfc..074906d8959 100644 --- a/storage/xtradb/include/fil0fil.h +++ b/storage/xtradb/include/fil0fil.h @@ -128,6 +128,8 @@ extern fil_addr_t fil_addr_null; at least up to this lsn */ #define FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID 34 /*!< starting from 4.1.x this contains the space id of the page */ +#define FIL_PAGE_SPACE_ID FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID + #define FIL_PAGE_DATA 38 /*!< start of the data on the page */ /* @} */ /** File page trailer @{ */ diff --git a/storage/xtradb/include/fts0priv.h b/storage/xtradb/include/fts0priv.h index c6aca27f6ec..b4d9e1d41ec 100644 --- a/storage/xtradb/include/fts0priv.h +++ b/storage/xtradb/include/fts0priv.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2013, 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 @@ -569,7 +569,10 @@ int fts_write_object_id( /*================*/ ib_id_t id, /*!< in: a table/index id */ - char* str) /*!< in: buffer to write the id to */ + char* str, /*!< in: buffer to write the id to */ + bool hex_format __attribute__((unused))) + /*!< in: true for fixed hex format, + false for old ambiguous format */ __attribute__((nonnull)); /******************************************************************//** Read the table id from the string generated by fts_write_object_id(). diff --git a/storage/xtradb/include/fts0priv.ic b/storage/xtradb/include/fts0priv.ic index 268bb7e2227..8ef877f267e 100644 --- a/storage/xtradb/include/fts0priv.ic +++ b/storage/xtradb/include/fts0priv.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2013, 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 @@ -32,9 +32,24 @@ int fts_write_object_id( /*================*/ ib_id_t id, /* in: a table/index id */ - char* str) /* in: buffer to write the id to */ + char* str, /* in: buffer to write the id to */ + bool hex_format __attribute__((unused))) + /* in: true for fixed hex format, + false for old ambiguous format */ { - // FIXME: Use ut_snprintf() +#ifdef _WIN32 + /* Use this to construct old(5.6.14 and 5.7.3) ambiguous + aux table names */ + DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name", + return(sprintf(str, "%016llu", id));); + + /* As above, but this is only for those tables failing to rename. */ + if (!hex_format) { + // FIXME: Use ut_snprintf(), so does following one. + return(sprintf(str, "%016llu", id)); + } +#endif /* _WIN32 */ + return(sprintf(str, UINT64PFx, id)); } @@ -48,6 +63,9 @@ fts_read_object_id( ib_id_t* id, /* out: an id */ const char* str) /* in: buffer to read from */ { + /* NOTE: this func doesn't care about whether current table + is set with HEX_NAME, the user of the id read here will check + if the id is HEX or DEC and do the right thing with it. */ return(sscanf(str, UINT64PFx, id) == 1); } diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h index 4599547439e..66a96282b69 100644 --- a/storage/xtradb/include/ha_prototypes.h +++ b/storage/xtradb/include/ha_prototypes.h @@ -420,16 +420,6 @@ innobase_fts_text_case_cmp( const void* p1, /*!< in: key */ const void* p2); /*!< in: node */ -/******************************************************************//** -compare two character string according to their charset. */ -UNIV_INTERN -int -innobase_fts_string_cmp( -/*====================*/ - const void* cs, /*!< in: Character set */ - const void* p1, /*!< in: key */ - const void* p2); /*!< in: node */ - /****************************************************************//** Get FTS field charset info from the field's prtype @return charset info */ diff --git a/storage/xtradb/include/log0recv.h b/storage/xtradb/include/log0recv.h index a1653c10999..e21599cffab 100644 --- a/storage/xtradb/include/log0recv.h +++ b/storage/xtradb/include/log0recv.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1997, 2013, 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 @@ -31,6 +31,7 @@ Created 9/20/1997 Heikki Tuuri #include "buf0types.h" #include "hash0hash.h" #include "log0log.h" +#include /******************************************************//** Checks the 4-byte checksum to the trailer checksum field of a log @@ -404,6 +405,14 @@ struct recv_addr_t{ hash_node_t addr_hash;/*!< hash node in the hash bucket chain */ }; +struct recv_dblwr_t { + void add(byte* page); + + byte* find_first_page(ulint space_id); + + std::list pages; /* Pages from double write buffer */ +}; + /** Recovery system data structure */ struct recv_sys_t{ #ifndef UNIV_HOTBACKUP @@ -468,6 +477,8 @@ struct recv_sys_t{ hash_table_t* addr_hash;/*!< hash table of file addresses of pages */ ulint n_addrs;/*!< number of not processed hashed file addresses in the hash table */ + + recv_dblwr_t dblwr; }; /** The recovery system */ diff --git a/storage/xtradb/include/mem0mem.h b/storage/xtradb/include/mem0mem.h index c36ef06b554..f30034f3074 100644 --- a/storage/xtradb/include/mem0mem.h +++ b/storage/xtradb/include/mem0mem.h @@ -92,18 +92,35 @@ void mem_close(void); /*===========*/ +#ifdef UNIV_DEBUG /**************************************************************//** Use this macro instead of the corresponding function! Macro for memory heap creation. */ -#define mem_heap_create(N) mem_heap_create_func(\ - (N), MEM_HEAP_DYNAMIC, __FILE__, __LINE__) +# define mem_heap_create(N) mem_heap_create_func( \ + (N), __FILE__, __LINE__, MEM_HEAP_DYNAMIC) /**************************************************************//** Use this macro instead of the corresponding function! Macro for memory heap creation. */ -#define mem_heap_create_typed(N, T) mem_heap_create_func(\ - (N), (T), __FILE__, __LINE__) +# define mem_heap_create_typed(N, T) mem_heap_create_func( \ + (N), __FILE__, __LINE__, (T)) + +#else /* UNIV_DEBUG */ +/**************************************************************//** +Use this macro instead of the corresponding function! Macro for memory +heap creation. */ + +# define mem_heap_create(N) mem_heap_create_func( \ + (N), MEM_HEAP_DYNAMIC) +/**************************************************************//** +Use this macro instead of the corresponding function! Macro for memory +heap creation. */ + +# define mem_heap_create_typed(N, T) mem_heap_create_func( \ + (N), (T)) + +#endif /* UNIV_DEBUG */ /**************************************************************//** Use this macro instead of the corresponding function! Macro for memory heap freeing. */ @@ -124,9 +141,11 @@ mem_heap_create_func( this means that a single user buffer of size n will fit in the block, 0 creates a default size block */ - ulint type, /*!< in: heap type */ +#ifdef UNIV_DEBUG const char* file_name, /*!< in: file name where created */ - ulint line); /*!< in: line where created */ + ulint line, /*!< in: line where created */ +#endif /* UNIV_DEBUG */ + ulint type); /*!< in: heap type */ /*****************************************************************//** NOTE: Use the corresponding macro instead of this function. Frees the space occupied by a memory heap. In the debug version erases the heap memory @@ -218,8 +237,14 @@ Macro for memory buffer allocation */ #define mem_zalloc(N) memset(mem_alloc(N), 0, (N)) -#define mem_alloc(N) mem_alloc_func((N), NULL, __FILE__, __LINE__) -#define mem_alloc2(N,S) mem_alloc_func((N), (S), __FILE__, __LINE__) +#ifdef UNIV_DEBUG +#define mem_alloc(N) mem_alloc_func((N), __FILE__, __LINE__, NULL) +#define mem_alloc2(N,S) mem_alloc_func((N), __FILE__, __LINE__, (S)) +#else /* UNIV_DEBUG */ +#define mem_alloc(N) mem_alloc_func((N), NULL) +#define mem_alloc2(N,S) mem_alloc_func((N), (S)) +#endif /* UNIV_DEBUG */ + /***************************************************************//** NOTE: Use the corresponding macro instead of this function. Allocates a single buffer of memory from the dynamic memory of @@ -231,10 +256,12 @@ void* mem_alloc_func( /*===========*/ ulint n, /*!< in: requested size in bytes */ - ulint* size, /*!< out: allocated size in bytes, - or NULL */ +#ifdef UNIV_DEBUG const char* file_name, /*!< in: file name where created */ - ulint line); /*!< in: line where created */ + ulint line, /*!< in: line where created */ +#endif /* UNIV_DEBUG */ + ulint* size); /*!< out: allocated size in bytes, + or NULL */ /**************************************************************//** Use this macro instead of the corresponding function! @@ -343,8 +370,10 @@ mem_validate_all_blocks(void); /** The info structure stored at the beginning of a heap block */ struct mem_block_info_t { ulint magic_n;/* magic number for debugging */ +#ifdef UNIV_DEBUG char file_name[8];/* file name where the mem heap was created */ ulint line; /*!< line number where the mem heap was created */ +#endif /* UNIV_DEBUG */ UT_LIST_BASE_NODE_T(mem_block_t) base; /* In the first block in the the list this is the base node of the list of blocks; in subsequent blocks this is undefined */ diff --git a/storage/xtradb/include/mem0mem.ic b/storage/xtradb/include/mem0mem.ic index 7f0e128cc40..0d983d69e1a 100644 --- a/storage/xtradb/include/mem0mem.ic +++ b/storage/xtradb/include/mem0mem.ic @@ -28,21 +28,34 @@ Created 6/8/1994 Heikki Tuuri # include "mem0pool.h" #endif /* !UNIV_HOTBACKUP */ +#ifdef UNIV_DEBUG +# define mem_heap_create_block(heap, n, type, file_name, line) \ + mem_heap_create_block_func(heap, n, file_name, line, type) +# define mem_heap_create_at(N, file_name, line) \ + mem_heap_create_func(N, file_name, line, MEM_HEAP_DYNAMIC) +#else /* UNIV_DEBUG */ +# define mem_heap_create_block(heap, n, type, file_name, line) \ + mem_heap_create_block_func(heap, n, type) +# define mem_heap_create_at(N, file_name, line) \ + mem_heap_create_func(N, MEM_HEAP_DYNAMIC) +#endif /* UNIV_DEBUG */ /***************************************************************//** Creates a memory heap block where data can be allocated. @return own: memory heap block, NULL if did not succeed (only possible for MEM_HEAP_BTR_SEARCH type heaps) */ UNIV_INTERN mem_block_t* -mem_heap_create_block( -/*==================*/ +mem_heap_create_block_func( +/*=======================*/ mem_heap_t* heap, /*!< in: memory heap or NULL if first block should be created */ ulint n, /*!< in: number of bytes needed for user data */ - ulint type, /*!< in: type of heap: MEM_HEAP_DYNAMIC or - MEM_HEAP_BUFFER */ +#ifdef UNIV_DEBUG const char* file_name,/*!< in: file name where created */ - ulint line); /*!< in: line where created */ + ulint line, /*!< in: line where created */ +#endif /* UNIV_DEBUG */ + ulint type); /*!< in: type of heap: MEM_HEAP_DYNAMIC or + MEM_HEAP_BUFFER */ /******************************************************************//** Frees a block from a memory heap. */ UNIV_INTERN @@ -421,9 +434,11 @@ mem_heap_create_func( this means that a single user buffer of size n will fit in the block, 0 creates a default size block */ - ulint type, /*!< in: heap type */ +#ifdef UNIV_DEBUG const char* file_name, /*!< in: file name where created */ - ulint line) /*!< in: line where created */ + ulint line, /*!< in: line where created */ +#endif /* UNIV_DEBUG */ + ulint type) /*!< in: heap type */ { mem_block_t* block; @@ -509,15 +524,17 @@ void* mem_alloc_func( /*===========*/ ulint n, /*!< in: desired number of bytes */ - ulint* size, /*!< out: allocated size in bytes, - or NULL */ +#ifdef UNIV_DEBUG const char* file_name, /*!< in: file name where created */ - ulint line) /*!< in: line where created */ + ulint line, /*!< in: line where created */ +#endif /* UNIV_DEBUG */ + ulint* size) /*!< out: allocated size in bytes, + or NULL */ { mem_heap_t* heap; void* buf; - heap = mem_heap_create_func(n, MEM_HEAP_DYNAMIC, file_name, line); + heap = mem_heap_create_at(n, file_name, line); /* Note that as we created the first block in the heap big enough for the buffer requested by the caller, the buffer will be in the diff --git a/storage/xtradb/include/os0file.h b/storage/xtradb/include/os0file.h index 136c7b35a0a..a75091589c6 100644 --- a/storage/xtradb/include/os0file.h +++ b/storage/xtradb/include/os0file.h @@ -1,6 +1,6 @@ /*********************************************************************** -Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, Percona Inc. Portions of this file contain modifications contributed and copyrighted @@ -155,6 +155,10 @@ enum os_file_create_t { #define OS_FILE_INSUFFICIENT_RESOURCE 78 #define OS_FILE_AIO_INTERRUPTED 79 #define OS_FILE_OPERATION_ABORTED 80 + +#define OS_FILE_ACCESS_VIOLATION 81 + +#define OS_FILE_ERROR_MAX 100 /* @} */ /** Types for aio operations @{ */ @@ -401,7 +405,8 @@ enum os_file_type_t { OS_FILE_TYPE_UNKNOWN = 0, OS_FILE_TYPE_FILE, /* regular file */ OS_FILE_TYPE_DIR, /* directory */ - OS_FILE_TYPE_LINK /* symbolic link */ + OS_FILE_TYPE_LINK, /* symbolic link */ + OS_FILE_TYPE_BLOCK /* block device */ }; /* Maximum path string length in bytes when referring to tables with in the diff --git a/storage/xtradb/include/os0sync.h b/storage/xtradb/include/os0sync.h index 51c4530bb5a..91ad7e3b860 100644 --- a/storage/xtradb/include/os0sync.h +++ b/storage/xtradb/include/os0sync.h @@ -374,6 +374,9 @@ compare to, new_val is the value to swap in. */ # define os_compare_and_swap_lint(ptr, old_val, new_val) \ os_compare_and_swap(ptr, old_val, new_val) +# define os_compare_and_swap_uint32(ptr, old_val, new_val) \ + os_compare_and_swap(ptr, old_val, new_val) + # ifdef HAVE_IB_ATOMIC_PTHREAD_T_GCC # define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ os_compare_and_swap(ptr, old_val, new_val) @@ -395,6 +398,9 @@ amount of increment. */ # define os_atomic_increment_lint(ptr, amount) \ os_atomic_increment(ptr, amount) +# define os_atomic_increment_uint32(ptr, amount ) \ + os_atomic_increment(ptr, amount) + # define os_atomic_increment_ulint(ptr, amount) \ os_atomic_increment(ptr, amount) @@ -407,6 +413,9 @@ amount to decrement. */ # define os_atomic_decrement(ptr, amount) \ __sync_sub_and_fetch(ptr, amount) +# define os_atomic_decrement_uint32(ptr, amount) \ + os_atomic_decrement(ptr, amount) + # define os_atomic_decrement_lint(ptr, amount) \ os_atomic_decrement(ptr, amount) @@ -439,6 +448,9 @@ intrinsics and running on Solaris >= 10 use Solaris atomics */ Returns true if swapped, ptr is pointer to target, old_val is value to compare to, new_val is the value to swap in. */ +# define os_compare_and_swap_uint32(ptr, old_val, new_val) \ + (atomic_cas_32(ptr, old_val, new_val) == old_val) + # define os_compare_and_swap_ulint(ptr, old_val, new_val) \ (atomic_cas_ulong(ptr, old_val, new_val) == old_val) @@ -467,6 +479,9 @@ compare to, new_val is the value to swap in. */ Returns the resulting value, ptr is pointer to target, amount is the amount of increment. */ +# define os_atomic_increment_uint32(ptr, amount) \ + atomic_add_32_nv(ptr, amount) + # define os_atomic_increment_ulint(ptr, amount) \ atomic_add_long_nv(ptr, amount) @@ -479,6 +494,9 @@ amount of increment. */ /* Returns the resulting value, ptr is pointer to target, amount is the amount to decrement. */ +# define os_atomic_decrement_uint32(ptr, amount) \ + os_atomic_increment_uint32(ptr, -(amount)) + # define os_atomic_decrement_lint(ptr, amount) \ os_atomic_increment_ulint((ulong_t*) ptr, -(amount)) @@ -555,6 +573,9 @@ win_cmp_and_xchg_dword( Returns true if swapped, ptr is pointer to target, old_val is value to compare to, new_val is the value to swap in. */ +# define os_compare_and_swap_uint32(ptr, old_val, new_val) \ + (win_cmp_and_xchg_dword(ptr, new_val, old_val) == old_val) + # define os_compare_and_swap_ulint(ptr, old_val, new_val) \ (win_cmp_and_xchg_ulint(ptr, new_val, old_val) == old_val) @@ -576,6 +597,9 @@ amount of increment. */ # define os_atomic_increment_lint(ptr, amount) \ (win_xchg_and_add(ptr, amount) + amount) +# define os_atomic_increment_uint32(ptr, amount) \ + ((ulint) _InterlockedExchangeAdd((long*) ptr, amount)) + # define os_atomic_increment_ulint(ptr, amount) \ ((ulint) (win_xchg_and_add((lint*) ptr, (lint) amount) + amount)) @@ -588,6 +612,9 @@ amount of increment. */ Returns the resulting value, ptr is pointer to target, amount is the amount to decrement. There is no atomic substract function on Windows */ +# define os_atomic_decrement_uint32(ptr, amount) \ + ((ulint) _InterlockedExchangeAdd((long*) ptr, (-amount))) + # define os_atomic_decrement_lint(ptr, amount) \ (win_xchg_and_add(ptr, -(lint) amount) - amount) diff --git a/storage/xtradb/include/page0page.h b/storage/xtradb/include/page0page.h index 80181bb5c30..6940040a130 100644 --- a/storage/xtradb/include/page0page.h +++ b/storage/xtradb/include/page0page.h @@ -1102,6 +1102,14 @@ page_find_rec_with_heap_no( /*=======================*/ const page_t* page, /*!< in: index page */ ulint heap_no);/*!< in: heap number */ +/** Get the last non-delete-marked record on a page. +@param[in] page index tree leaf page +@return the last record, not delete-marked +@retval infimum record if all records are delete-marked */ + +const rec_t* +page_find_rec_max_not_deleted( + const page_t* page); #ifdef UNIV_MATERIALIZE #undef UNIV_INLINE #define UNIV_INLINE UNIV_INLINE_ORIGINAL diff --git a/storage/xtradb/include/page0page.ic b/storage/xtradb/include/page0page.ic index 58add015d34..4a22a32112f 100644 --- a/storage/xtradb/include/page0page.ic +++ b/storage/xtradb/include/page0page.ic @@ -417,6 +417,8 @@ page_rec_is_user_rec( /*=================*/ const rec_t* rec) /*!< in: record */ { + ut_ad(page_rec_check(rec)); + return(page_rec_is_user_rec_low(page_offset(rec))); } @@ -429,6 +431,8 @@ page_rec_is_supremum( /*=================*/ const rec_t* rec) /*!< in: record */ { + ut_ad(page_rec_check(rec)); + return(page_rec_is_supremum_low(page_offset(rec))); } @@ -441,6 +445,8 @@ page_rec_is_infimum( /*================*/ const rec_t* rec) /*!< in: record */ { + ut_ad(page_rec_check(rec)); + return(page_rec_is_infimum_low(page_offset(rec))); } diff --git a/storage/xtradb/include/rem0rec.h b/storage/xtradb/include/rem0rec.h index 2a84aee7a6f..8e7d5ff2d48 100644 --- a/storage/xtradb/include/rem0rec.h +++ b/storage/xtradb/include/rem0rec.h @@ -440,13 +440,24 @@ rec_get_offsets_func( ulint n_fields,/*!< in: maximum number of initialized fields (ULINT_UNDEFINED if all fields) */ - mem_heap_t** heap, /*!< in/out: memory heap */ +#ifdef UNIV_DEBUG const char* file, /*!< in: file name where called */ - ulint line) /*!< in: line number where called */ - __attribute__((nonnull(1,2,5,6),warn_unused_result)); + ulint line, /*!< in: line number where called */ +#endif /* UNIV_DEBUG */ + mem_heap_t** heap) /*!< in/out: memory heap */ +#ifdef UNIV_DEBUG + __attribute__((nonnull(1,2,5,7),warn_unused_result)); +#else /* UNIV_DEBUG */ + __attribute__((nonnull(1,2,5),warn_unused_result)); +#endif /* UNIV_DEBUG */ -#define rec_get_offsets(rec,index,offsets,n,heap) \ - rec_get_offsets_func(rec,index,offsets,n,heap,__FILE__,__LINE__) +#ifdef UNIV_DEBUG +# define rec_get_offsets(rec,index,offsets,n,heap) \ + rec_get_offsets_func(rec,index,offsets,n,__FILE__,__LINE__,heap) +#else /* UNIV_DEBUG */ +# define rec_get_offsets(rec, index, offsets, n, heap) \ + rec_get_offsets_func(rec, index, offsets, n, heap) +#endif /* UNIV_DEBUG */ /******************************************************//** The following function determines the offsets to each field diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index ff881b3fdff..59ec5b70f8a 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2008, 2009, Google Inc. Copyright (c) 2009, Percona Inc. @@ -454,8 +454,8 @@ expected. */ extern ulint srv_read_views_memory; extern ulint srv_descriptors_memory; -extern ibool srv_print_innodb_monitor; -extern ibool srv_print_innodb_lock_monitor; +extern my_bool srv_print_innodb_monitor; +extern my_bool srv_print_innodb_lock_monitor; extern ibool srv_print_innodb_tablespace_monitor; extern ibool srv_print_verbose_log; #define DEPRECATED_MSG_INNODB_TABLE_MONITOR \ @@ -529,6 +529,9 @@ extern const char* srv_io_thread_function[]; /* The tid of the cleaner thread */ extern os_tid_t srv_cleaner_tid; +/* The tid of the LRU manager thread */ +extern os_tid_t srv_lru_manager_tid; + /* The tids of the purge threads */ extern os_tid_t srv_purge_tids[]; @@ -538,7 +541,7 @@ extern os_tid_t srv_io_tids[]; /* The tid of the master thread */ extern os_tid_t srv_master_tid; -/* The relative scheduling priority of the cleaner thread */ +/* The relative scheduling priority of the cleaner and LRU manager threads */ extern ulint srv_sched_priority_cleaner; /* The relative scheduling priority of the purge threads */ @@ -590,6 +593,7 @@ extern my_bool srv_fake_changes_locks; # ifdef UNIV_PFS_THREAD /* Keys to register InnoDB threads with performance schema */ extern mysql_pfs_key_t buf_page_cleaner_thread_key; +extern mysql_pfs_key_t buf_lru_manager_thread_key; extern mysql_pfs_key_t trx_rollback_clean_thread_key; extern mysql_pfs_key_t io_handler_thread_key; extern mysql_pfs_key_t srv_lock_timeout_thread_key; diff --git a/storage/xtradb/include/sync0rw.h b/storage/xtradb/include/sync0rw.h index a215d4d3f60..95bb7e16b26 100644 --- a/storage/xtradb/include/sync0rw.h +++ b/storage/xtradb/include/sync0rw.h @@ -182,6 +182,9 @@ unlocking, not the corresponding function. */ # define rw_lock_s_lock_gen(M, P) \ rw_lock_s_lock_func((M), (P), __FILE__, __LINE__) +# define rw_lock_s_lock_gen_nowait(M, P) \ + rw_lock_s_lock_low((M), (P), __FILE__, __LINE__) + # define rw_lock_s_lock_nowait(M, F, L) \ rw_lock_s_lock_low((M), 0, (F), (L)) @@ -244,6 +247,9 @@ unlocking, not the corresponding function. */ # define rw_lock_s_lock_gen(M, P) \ pfs_rw_lock_s_lock_func((M), (P), __FILE__, __LINE__) +# define rw_lock_s_lock_gen_nowait(M, P) \ + pfs_rw_lock_s_lock_low((M), (P), __FILE__, __LINE__) + # define rw_lock_s_lock_nowait(M, F, L) \ pfs_rw_lock_s_lock_low((M), 0, (F), (L)) diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h index 259fcd0cf6e..aaa74724a14 100644 --- a/storage/xtradb/include/trx0trx.h +++ b/storage/xtradb/include/trx0trx.h @@ -857,8 +857,7 @@ struct trx_t{ when trx->in_rw_trx_list. Initially set to TRX_ID_MAX. */ - time_t start_time; /*!< time the trx object was created - or the state last time became + time_t start_time; /*!< time the trx state last time became TRX_STATE_ACTIVE */ trx_id_t id; /*!< transaction id */ XID xid; /*!< X/Open XA transaction diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i index eaf2262481c..eded44789a8 100644 --- a/storage/xtradb/include/univ.i +++ b/storage/xtradb/include/univ.i @@ -44,10 +44,10 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 5 #define INNODB_VERSION_MINOR 6 -#define INNODB_VERSION_BUGFIX 15 +#define INNODB_VERSION_BUGFIX 16 #ifndef PERCONA_INNODB_VERSION -#define PERCONA_INNODB_VERSION 63.0 +#define PERCONA_INNODB_VERSION 64.2 #endif /* Enable UNIV_LOG_ARCHIVE in XtraDB */ @@ -447,7 +447,7 @@ macro ULINTPF. */ # define UINT32PF "%I32u" # define INT64PF "%I64d" # define UINT64PF "%I64u" -# define UINT64PFx "%016I64u" +# define UINT64PFx "%016I64x" # define DBUG_LSN_PF "%llu" typedef __int64 ib_int64_t; typedef unsigned __int64 ib_uint64_t; diff --git a/storage/xtradb/log/log0recv.cc b/storage/xtradb/log/log0recv.cc index cb4b988e46c..bf239299268 100644 --- a/storage/xtradb/log/log0recv.cc +++ b/storage/xtradb/log/log0recv.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1997, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. This program is free software; you can redistribute it and/or modify it under @@ -24,6 +24,11 @@ Recovery Created 9/20/1997 Heikki Tuuri *******************************************************/ +// First include (the generated) my_config.h, to get correct platform defines. +#include "my_config.h" +#include // Solaris/x86 header file bug + +#include #include "log0recv.h" #ifdef UNIV_NONINL @@ -59,6 +64,7 @@ Created 9/20/1997 Heikki Tuuri # include "sync0sync.h" #else /* !UNIV_HOTBACKUP */ + /** This is set to FALSE if the backup was originally taken with the ibbackup --include regexp option: then we do not want to create tables in directories which were not included */ @@ -429,6 +435,9 @@ recv_sys_init( recv_max_page_lsn = 0; + /* Call the constructor for recv_sys_t::dblwr member */ + new (&recv_sys->dblwr) recv_dblwr_t(); + mutex_exit(&(recv_sys->mutex)); } @@ -1379,14 +1388,23 @@ recv_parse_or_apply_log_rec_body( ptr = mlog_parse_string(ptr, end_ptr, page, page_zip); break; case MLOG_FILE_RENAME: - ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type, - (recv_recovery_is_on() - ? space_id : 0), 0); + /* Do not rerun file-based log entries if this is + IO completion from a page read. */ + if (page == NULL) { + ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type, + (recv_recovery_is_on() + ? space_id : 0), 0); + } break; case MLOG_FILE_CREATE: case MLOG_FILE_DELETE: case MLOG_FILE_CREATE2: - ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type, 0, 0); + /* Do not rerun file-based log entries if this is + IO completion from a page read. */ + if (page == NULL) { + ptr = fil_op_log_parse_or_replay(ptr, end_ptr, + type, 0, 0); + } break; case MLOG_ZIP_WRITE_NODE_PTR: ut_ad(!page || page_type == FIL_PAGE_INDEX); @@ -3024,6 +3042,8 @@ recv_init_crash_recovery(void) ib_logf(IB_LOG_LEVEL_INFO, "Reading tablespace information from the .ibd files..."); + buf_dblwr_init_or_load_pages(true); + fil_load_single_table_tablespaces(); /* If we are using the doublewrite method, we will @@ -3039,7 +3059,7 @@ recv_init_crash_recovery(void) ib_logf(IB_LOG_LEVEL_INFO, "from the doublewrite buffer..."); - buf_dblwr_init_or_restore_pages(TRUE); + buf_dblwr_process(); /* Spawn the background thread to flush dirty pages from the buffer pools. */ @@ -3355,7 +3375,7 @@ recv_recovery_from_checkpoint_start_func( if (!recv_needed_recovery && !srv_read_only_mode) { /* Init the doublewrite buffer memory structure */ - buf_dblwr_init_or_restore_pages(FALSE); + buf_dblwr_init_or_load_pages(false); } } @@ -4059,3 +4079,46 @@ recv_recovery_from_archive_finish(void) recv_recovery_from_backup_on = FALSE; } #endif /* UNIV_LOG_ARCHIVE */ + + +void recv_dblwr_t::add(byte* page) +{ + pages.push_back(page); +} + +byte* recv_dblwr_t::find_first_page(ulint space_id) +{ + std::vector matches; + byte* result = 0; + + for (std::list::iterator i = pages.begin(); + i != pages.end(); ++i) { + + if ((page_get_space_id(*i) == space_id) + && (page_get_page_no(*i) == 0)) { + matches.push_back(*i); + } + } + + if (matches.size() == 1) { + result = matches[0]; + } else if (matches.size() > 1) { + + lsn_t max_lsn = 0; + lsn_t page_lsn = 0; + + for (std::vector::iterator i = matches.begin(); + i != matches.end(); ++i) { + + page_lsn = mach_read_from_8(*i + FIL_PAGE_LSN); + + if (page_lsn > max_lsn) { + max_lsn = page_lsn; + result = *i; + } + } + } + + return(result); +} + diff --git a/storage/xtradb/mem/mem0mem.cc b/storage/xtradb/mem/mem0mem.cc index e0e6220f4d8..e066aff5b30 100644 --- a/storage/xtradb/mem/mem0mem.cc +++ b/storage/xtradb/mem/mem0mem.cc @@ -299,15 +299,17 @@ Creates a memory heap block where data can be allocated. for MEM_HEAP_BTR_SEARCH type heaps) */ UNIV_INTERN mem_block_t* -mem_heap_create_block( -/*==================*/ +mem_heap_create_block_func( +/*=======================*/ mem_heap_t* heap, /*!< in: memory heap or NULL if first block should be created */ ulint n, /*!< in: number of bytes needed for user data */ - ulint type, /*!< in: type of heap: MEM_HEAP_DYNAMIC or - MEM_HEAP_BUFFER */ +#ifdef UNIV_DEBUG const char* file_name,/*!< in: file name where created */ - ulint line) /*!< in: line where created */ + ulint line, /*!< in: line where created */ +#endif /* UNIV_DEBUG */ + ulint type) /*!< in: type of heap: MEM_HEAP_DYNAMIC or + MEM_HEAP_BUFFER */ { #ifndef UNIV_HOTBACKUP buf_block_t* buf_block = NULL; @@ -368,8 +370,9 @@ mem_heap_create_block( #endif /* !UNIV_HOTBACKUP */ block->magic_n = MEM_BLOCK_MAGIC_N; - ut_strlcpy_rev(block->file_name, file_name, sizeof(block->file_name)); - block->line = line; + ut_d(ut_strlcpy_rev(block->file_name, file_name, + sizeof(block->file_name))); + ut_d(block->line = line); #ifdef MEM_PERIODIC_CHECK mutex_enter(&(mem_comm_pool->mutex)); diff --git a/storage/xtradb/mtr/mtr0log.cc b/storage/xtradb/mtr/mtr0log.cc index 5335cb4c9ef..0660c819240 100644 --- a/storage/xtradb/mtr/mtr0log.cc +++ b/storage/xtradb/mtr/mtr0log.cc @@ -560,7 +560,7 @@ mlog_parse_index( n = n_uniq = 1; } table = dict_mem_table_create("LOG_DUMMY", DICT_HDR_SPACE, n, - comp ? DICT_TF_COMPACT : 0, 0); + comp ? DICT_TF_COMPACT : 0, 0, true); ind = dict_mem_index_create("LOG_DUMMY", "LOG_DUMMY", DICT_HDR_SPACE, 0, n); ind->table = table; diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index 8c09beb3e9c..6ba19879847 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -563,8 +563,10 @@ os_file_get_last_error_low( return(OS_FILE_INSUFFICIENT_RESOURCE); } else if (err == ERROR_OPERATION_ABORTED) { return(OS_FILE_OPERATION_ABORTED); + } else if (err == ERROR_ACCESS_DENIED) { + return(OS_FILE_ACCESS_VIOLATION); } else { - return(100 + err); + return(OS_FILE_ERROR_MAX + err); } #else int err = errno; @@ -638,8 +640,10 @@ os_file_get_last_error_low( return(OS_FILE_AIO_INTERRUPTED); } break; + case EACCES: + return(OS_FILE_ACCESS_VIOLATION); } - return(100 + err); + return(OS_FILE_ERROR_MAX + err); #endif } @@ -717,6 +721,7 @@ os_file_handle_error_cond_exit( case OS_FILE_PATH_ERROR: case OS_FILE_ALREADY_EXISTS: + case OS_FILE_ACCESS_VIOLATION: return(FALSE); @@ -2587,12 +2592,13 @@ os_file_pread( os_mutex_exit(os_file_count_mutex); #endif /* HAVE_ATOMIC_BUILTINS && UNIV_WORD == 8 */ - /* Handle signal interruptions correctly */ + /* Handle partial reads and signal interruptions correctly */ for (n_bytes = 0; n_bytes < (ssize_t) n; ) { - n_read = pread(file, buf, (ssize_t)n, offs); + n_read = pread(file, buf, (ssize_t)n - n_bytes, offs); if (n_read > 0) { n_bytes += n_read; offs += n_read; + buf = (char *)buf + n_read; } else if (n_read == -1 && errno == EINTR) { continue; } else { @@ -2734,12 +2740,13 @@ os_file_pwrite( MONITOR_ATOMIC_INC(MONITOR_OS_PENDING_WRITES); #endif /* !HAVE_ATOMIC_BUILTINS || UNIV_WORD < 8 */ - /* Handle signal interruptions correctly */ + /* Handle partial writes and signal interruptions correctly */ for (ret = 0; ret < (ssize_t) n; ) { - n_written = pwrite(file, buf, (ssize_t)n, offs); - if (n_written > 0) { + n_written = pwrite(file, buf, (ssize_t)n - ret, offs); + if (n_written >= 0) { ret += n_written; offs += n_written; + buf = (char *)buf + n_written; } else if (n_written == -1 && errno == EINTR) { continue; } else { @@ -3333,32 +3340,43 @@ os_file_get_status( return(DB_FAIL); - } else if (S_ISDIR(statinfo.st_mode)) { + } + + switch (statinfo.st_mode & S_IFMT) { + case S_IFDIR: stat_info->type = OS_FILE_TYPE_DIR; - } else if (S_ISLNK(statinfo.st_mode)) { + break; + case S_IFLNK: stat_info->type = OS_FILE_TYPE_LINK; - } else if (S_ISREG(statinfo.st_mode)) { + break; + case S_IFBLK: + stat_info->type = OS_FILE_TYPE_BLOCK; + break; + case S_IFREG: stat_info->type = OS_FILE_TYPE_FILE; - - if (check_rw_perm) { - int fh; - int access; - - access = !srv_read_only_mode ? O_RDWR : O_RDONLY; - - fh = ::open(path, access, os_innodb_umask); - - if (fh == -1) { - stat_info->rw_perm = false; - } else { - stat_info->rw_perm = true; - close(fh); - } - } - } else { + break; + default: stat_info->type = OS_FILE_TYPE_UNKNOWN; } + + if (check_rw_perm && (stat_info->type == OS_FILE_TYPE_FILE + || stat_info->type == OS_FILE_TYPE_BLOCK)) { + int fh; + int access; + + access = !srv_read_only_mode ? O_RDWR : O_RDONLY; + + fh = ::open(path, access, os_innodb_umask); + + if (fh == -1) { + stat_info->rw_perm = false; + } else { + stat_info->rw_perm = true; + close(fh); + } + } + #endif /* _WIN_ */ stat_info->ctime = statinfo.st_ctime; @@ -5154,6 +5172,7 @@ os_aio_linux_handle( segment = os_aio_get_array_and_local_segment(&array, global_seg); n = array->n_slots / array->n_segments; + wait_for_event: /* Loop until we have found a completed request. */ for (;;) { ibool any_reserved = FALSE; @@ -5216,6 +5235,41 @@ found: if (slot->ret == 0 && slot->n_bytes == (long) slot->len) { ret = TRUE; + } else if ((slot->ret == 0) && (slot->n_bytes > 0) + && (slot->n_bytes < (long) slot->len)) { + /* Partial read or write scenario */ + int submit_ret; + struct iocb* iocb; + slot->buf = (byte*)slot->buf + slot->n_bytes; + slot->offset = slot->offset + slot->n_bytes; + slot->len = slot->len - slot->n_bytes; + /* Resetting the bytes read/written */ + slot->n_bytes = 0; + slot->io_already_done = FALSE; + iocb = &(slot->control); + + if (slot->type == OS_FILE_READ) { + io_prep_pread(&slot->control, slot->file, slot->buf, + slot->len, (off_t) slot->offset); + } else { + ut_a(slot->type == OS_FILE_WRITE); + io_prep_pwrite(&slot->control, slot->file, slot->buf, + slot->len, (off_t) slot->offset); + } + /* Resubmit an I/O request */ + submit_ret = io_submit(array->aio_ctx[segment], 1, &iocb); + if (submit_ret < 0 ) { + /* Aborting in case of submit failure */ + ib_logf(IB_LOG_LEVEL_FATAL, + "Native Linux AIO interface. io_submit()" + " call failed when resubmitting a partial" + " I/O request on the file %s.", + slot->name); + } else { + ret = FALSE; + os_mutex_exit(array->mutex); + goto wait_for_event; + } } else { errno = -slot->ret; diff --git a/storage/xtradb/page/page0cur.cc b/storage/xtradb/page/page0cur.cc index efce1f10cae..f5f7e1299ce 100644 --- a/storage/xtradb/page/page0cur.cc +++ b/storage/xtradb/page/page0cur.cc @@ -977,7 +977,8 @@ page_cur_insert_rec_low( == (ibool) !!page_is_comp(page)); ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX); ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) - == index->id || recv_recovery_is_on() || mtr->inside_ibuf); + == index->id || recv_recovery_is_on() + || (mtr ? mtr->inside_ibuf : dict_index_is_ibuf(index))); ut_ad(!page_rec_is_supremum(current_rec)); @@ -1204,7 +1205,8 @@ page_cur_insert_rec_zip( ut_ad(page_is_comp(page)); ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX); ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) - == index->id || mtr->inside_ibuf || recv_recovery_is_on()); + == index->id || recv_recovery_is_on() + || (mtr ? mtr->inside_ibuf : dict_index_is_ibuf(index))); ut_ad(!page_cur_is_after_last(cursor)); #ifdef UNIV_ZIP_DEBUG @@ -1977,7 +1979,8 @@ page_cur_delete_rec( const dict_index_t* index, /*!< in: record descriptor */ const ulint* offsets,/*!< in: rec_get_offsets( cursor->rec, index) */ - mtr_t* mtr) /*!< in: mini-transaction handle */ + mtr_t* mtr) /*!< in: mini-transaction handle + or NULL */ { page_dir_slot_t* cur_dir_slot; page_dir_slot_t* prev_slot; @@ -2006,7 +2009,8 @@ page_cur_delete_rec( ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table)); ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX); ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) - == index->id || mtr->inside_ibuf || recv_recovery_is_on()); + == index->id || recv_recovery_is_on() + || (mtr ? mtr->inside_ibuf : dict_index_is_ibuf(index))); /* The record must not be the supremum or infimum record. */ ut_ad(page_rec_is_user_rec(current_rec)); diff --git a/storage/xtradb/page/page0page.cc b/storage/xtradb/page/page0page.cc index 2faf804279c..bd5fb36af8f 100644 --- a/storage/xtradb/page/page0page.cc +++ b/storage/xtradb/page/page0page.cc @@ -2779,3 +2779,35 @@ page_delete_rec( return(no_compress_needed); } +/** Get the last non-delete-marked record on a page. +@param[in] page index tree leaf page +@return the last record, not delete-marked +@retval infimum record if all records are delete-marked */ + +const rec_t* +page_find_rec_max_not_deleted( + const page_t* page) +{ + const rec_t* rec = page_get_infimum_rec(page); + const rec_t* prev_rec = NULL; // remove warning + + /* Because the page infimum is never delete-marked, + prev_rec will always be assigned to it first. */ + ut_ad(!rec_get_deleted_flag(rec, page_rec_is_comp(rec))); + if (page_is_comp(page)) { + do { + if (!rec_get_deleted_flag(rec, true)) { + prev_rec = rec; + } + rec = page_rec_get_next_low(rec, true); + } while (rec != page + PAGE_NEW_SUPREMUM); + } else { + do { + if (!rec_get_deleted_flag(rec, false)) { + prev_rec = rec; + } + rec = page_rec_get_next_low(rec, false); + } while (rec != page + PAGE_OLD_SUPREMUM); + } + return(prev_rec); +} diff --git a/storage/xtradb/page/page0zip.cc b/storage/xtradb/page/page0zip.cc index 81c9e0ab45a..ed73fb37d41 100644 --- a/storage/xtradb/page/page0zip.cc +++ b/storage/xtradb/page/page0zip.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2005, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2005, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. This program is free software; you can redistribute it and/or modify it under @@ -24,6 +24,9 @@ Compressed page interface Created June 2005 by Marko Makela *******************************************************/ +// First include (the generated) my_config.h, to get correct platform defines. +#include "my_config.h" + #include using namespace std; @@ -1571,9 +1574,8 @@ page_zip_fields_free( dict_table_t* table = index->table; os_fast_mutex_free(&index->zip_pad.mutex); mem_heap_free(index->heap); - mutex_free(&(table->autoinc_mutex)); - ut_free(table->name); - mem_heap_free(table->heap); + + dict_mem_table_free(table); } } @@ -1621,7 +1623,7 @@ page_zip_fields_decode( } table = dict_mem_table_create("ZIP_DUMMY", DICT_HDR_SPACE, n, - DICT_TF_COMPACT, 0); + DICT_TF_COMPACT, 0, true); index = dict_mem_index_create("ZIP_DUMMY", "ZIP_DUMMY", DICT_HDR_SPACE, 0, n); index->table = table; @@ -4898,8 +4900,12 @@ page_zip_verify_checksum( /* declare empty pages non-corrupted */ if (stored == 0) { /* make sure that the page is really empty */ - ut_d(ulint i; for (i = 0; i < size; i++) { - ut_a(*((const char*) data + i) == 0); }); + ulint i; + for (i = 0; i < size; i++) { + if (*((const char*) data + i) != 0) { + return(FALSE); + } + } return(TRUE); } diff --git a/storage/xtradb/pars/pars0pars.cc b/storage/xtradb/pars/pars0pars.cc index e0bc00fad0d..fff0b1efd01 100644 --- a/storage/xtradb/pars/pars0pars.cc +++ b/storage/xtradb/pars/pars0pars.cc @@ -1988,10 +1988,16 @@ pars_create_table( } } + /* Set the flags2 when create table or alter tables */ + flags2 |= DICT_TF2_FTS_AUX_HEX_NAME; + DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name", + flags2 &= ~DICT_TF2_FTS_AUX_HEX_NAME;); + + n_cols = que_node_list_get_len(column_defs); table = dict_mem_table_create( - table_sym->name, 0, n_cols, flags, flags2); + table_sym->name, 0, n_cols, flags, flags2, false); #ifdef UNIV_DEBUG if (not_fit_in_memory != NULL) { diff --git a/storage/xtradb/rem/rem0rec.cc b/storage/xtradb/rem/rem0rec.cc index 43072159b9e..0d7b7c16785 100644 --- a/storage/xtradb/rem/rem0rec.cc +++ b/storage/xtradb/rem/rem0rec.cc @@ -543,9 +543,11 @@ rec_get_offsets_func( ulint n_fields,/*!< in: maximum number of initialized fields (ULINT_UNDEFINED if all fields) */ - mem_heap_t** heap, /*!< in/out: memory heap */ +#ifdef UNIV_DEBUG const char* file, /*!< in: file name where called */ - ulint line) /*!< in: line number where called */ + ulint line, /*!< in: line number where called */ +#endif /* UNIV_DEBUG */ + mem_heap_t** heap) /*!< in/out: memory heap */ { ulint n; ulint size; @@ -590,9 +592,8 @@ rec_get_offsets_func( if (UNIV_UNLIKELY(!offsets) || UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) { if (UNIV_UNLIKELY(!*heap)) { - *heap = mem_heap_create_func(size * sizeof(ulint), - MEM_HEAP_DYNAMIC, - file, line); + *heap = mem_heap_create_at(size * sizeof(ulint), + file, line); } offsets = static_cast( mem_heap_alloc(*heap, size * sizeof(ulint))); diff --git a/storage/xtradb/row/row0ftsort.cc b/storage/xtradb/row/row0ftsort.cc index 7a673feae9b..be62aa34a07 100644 --- a/storage/xtradb/row/row0ftsort.cc +++ b/storage/xtradb/row/row0ftsort.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2010, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2010, 2013, 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 @@ -1434,11 +1434,17 @@ row_fts_merge_insert( ins_ctx.ins_graph = static_cast(mem_heap_alloc(heap, n_bytes)); memset(ins_ctx.ins_graph, 0x0, n_bytes); + /* We should set the flags2 with aux_table_name here, + in order to get the correct aux table names. */ + index->table->flags2 |= DICT_TF2_FTS_AUX_HEX_NAME; + DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name", + index->table->flags2 &= ~DICT_TF2_FTS_AUX_HEX_NAME;); + ins_ctx.fts_table.type = FTS_INDEX_TABLE; ins_ctx.fts_table.index_id = index->id; ins_ctx.fts_table.table_id = table->id; ins_ctx.fts_table.parent = index->table->name; - ins_ctx.fts_table.table = NULL; + ins_ctx.fts_table.table = index->table; for (i = 0; i < fts_sort_pll_degree; i++) { if (psort_info[i].merge_file[id]->n_rec == 0) { diff --git a/storage/xtradb/row/row0log.cc b/storage/xtradb/row/row0log.cc index 0c5ae2d3125..3a01b5ed55a 100644 --- a/storage/xtradb/row/row0log.cc +++ b/storage/xtradb/row/row0log.cc @@ -78,11 +78,12 @@ struct row_log_buf_t { mrec_buf_t buf; /*!< buffer for accessing a record that spans two blocks */ ulint blocks; /*!< current position in blocks */ - ulint bytes; /*!< current position within buf */ + ulint bytes; /*!< current position within block */ ulonglong total; /*!< logical position, in bytes from the start of the row_log_table log; 0 for row_log_online_op() and row_log_apply(). */ + ulint size; /*!< allocated size of block */ }; /** Tracks BLOB allocation during online ALTER TABLE */ @@ -193,9 +194,48 @@ struct row_log_t { or by index->lock X-latch only */ row_log_buf_t head; /*!< reader context; protected by MDL only; modifiable by row_log_apply_ops() */ - ulint size; /*!< allocated size */ }; + +/** Allocate the memory for the log buffer. +@param[in,out] log_buf Buffer used for log operation +@return TRUE if success, false if not */ +static __attribute__((warn_unused_result)) +bool +row_log_block_allocate( + row_log_buf_t& log_buf) +{ + DBUG_ENTER("row_log_block_allocate"); + if (log_buf.block == NULL) { + log_buf.size = srv_sort_buf_size; + log_buf.block = (byte*) os_mem_alloc_large(&log_buf.size, + FALSE); + DBUG_EXECUTE_IF("simulate_row_log_allocation_failure", + if (log_buf.block) + os_mem_free_large(log_buf.block, log_buf.size); + log_buf.block = NULL;); + if (!log_buf.block) { + DBUG_RETURN(false); + } + } + DBUG_RETURN(true); +} + +/** Free the log buffer. +@param[in,out] log_buf Buffer used for log operation */ +static +void +row_log_block_free( + row_log_buf_t& log_buf) +{ + DBUG_ENTER("row_log_block_free"); + if (log_buf.block != NULL) { + os_mem_free_large(log_buf.block, log_buf.size); + log_buf.block = NULL; + } + DBUG_VOID_RETURN; +} + /******************************************************//** Logs an operation to a secondary index that is (or was) being created. */ UNIV_INTERN @@ -247,6 +287,11 @@ row_log_online_op( log->max_trx = trx_id; } + if (!row_log_block_allocate(log->tail)) { + log->error = DB_OUT_OF_MEMORY; + goto err_exit; + } + UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf); ut_ad(log->tail.bytes < srv_sort_buf_size); @@ -318,6 +363,7 @@ write_failed: } UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf); +err_exit: mutex_exit(&log->mutex); } @@ -352,10 +398,16 @@ row_log_table_open( UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf); if (log->error != DB_SUCCESS) { +err_exit: mutex_exit(&log->mutex); return(NULL); } + if (!row_log_block_allocate(log->tail)) { + log->error = DB_OUT_OF_MEMORY; + goto err_exit; + } + ut_ad(log->tail.bytes < srv_sort_buf_size); *avail = srv_sort_buf_size - log->tail.bytes; @@ -2266,7 +2318,9 @@ corruption: if (index->online_log->head.blocks) { #ifdef HAVE_FTRUNCATE /* Truncate the file in order to save space. */ - ftruncate(index->online_log->fd, 0); + if (ftruncate(index->online_log->fd, 0) == -1) { + perror("ftruncate"); + } #endif /* HAVE_FTRUNCATE */ index->online_log->head.blocks = index->online_log->tail.blocks = 0; @@ -2301,6 +2355,11 @@ all_done: ut_ad(dict_index_is_online_ddl(index)); + if (!row_log_block_allocate(index->online_log->head)) { + error = DB_OUT_OF_MEMORY; + goto func_exit; + } + success = os_file_read_no_error_handling( OS_FILE_FROM_FD(index->online_log->fd), index->online_log->head.block, ofs, @@ -2504,6 +2563,7 @@ func_exit: mem_heap_free(offsets_heap); mem_heap_free(heap); + row_log_block_free(index->online_log->head); ut_free(offsets); return(error); } @@ -2577,9 +2637,7 @@ row_log_allocate( const ulint* col_map)/*!< in: mapping of old column numbers to new ones, or NULL if !table */ { - byte* buf; row_log_t* log; - ulint size; DBUG_ENTER("row_log_allocate"); ut_ad(!dict_index_is_online_ddl(index)); @@ -2591,17 +2649,14 @@ row_log_allocate( #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(dict_index_get_lock(index), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - size = 2 * srv_sort_buf_size + sizeof *log; - buf = (byte*) os_mem_alloc_large(&size, FALSE); - if (!buf) { + log = (row_log_t*) ut_malloc(sizeof *log); + if (!log) { DBUG_RETURN(false); } - log = (row_log_t*) &buf[2 * srv_sort_buf_size]; - log->size = size; log->fd = row_merge_file_create_low(); if (log->fd < 0) { - os_mem_free_large(buf, size); + ut_free(log); DBUG_RETURN(false); } mutex_create(index_online_log_key, &log->mutex, @@ -2613,10 +2668,9 @@ row_log_allocate( log->col_map = col_map; log->error = DB_SUCCESS; log->max_trx = 0; - log->head.block = buf; - log->tail.block = buf + srv_sort_buf_size; log->tail.blocks = log->tail.bytes = 0; log->tail.total = 0; + log->tail.block = log->head.block = NULL; log->head.blocks = log->head.bytes = 0; log->head.total = 0; dict_index_set_online_status(index, ONLINE_INDEX_CREATION); @@ -2641,9 +2695,11 @@ row_log_free( MONITOR_ATOMIC_DEC(MONITOR_ONLINE_CREATE_INDEX); delete log->blobs; + row_log_block_free(log->tail); + row_log_block_free(log->head); row_merge_file_destroy_low(log->fd); mutex_free(&log->mutex); - os_mem_free_large(log->head.block, log->size); + ut_free(log); log = 0; } @@ -3069,6 +3125,11 @@ next_block: goto interrupted; } + error = index->online_log->error; + if (error != DB_SUCCESS) { + goto func_exit; + } + if (dict_index_is_corrupted(index)) { error = DB_INDEX_CORRUPT; goto func_exit; @@ -3089,7 +3150,9 @@ corruption: if (index->online_log->head.blocks) { #ifdef HAVE_FTRUNCATE /* Truncate the file in order to save space. */ - ftruncate(index->online_log->fd, 0); + if (ftruncate(index->online_log->fd, 0) == -1) { + perror("ftruncate"); + } #endif /* HAVE_FTRUNCATE */ index->online_log->head.blocks = index->online_log->tail.blocks = 0; @@ -3120,6 +3183,11 @@ all_done: log_free_check(); + if (!row_log_block_allocate(index->online_log->head)) { + error = DB_OUT_OF_MEMORY; + goto func_exit; + } + success = os_file_read_no_error_handling( OS_FILE_FROM_FD(index->online_log->fd), index->online_log->head.block, ofs, @@ -3320,6 +3388,7 @@ func_exit: mem_heap_free(heap); mem_heap_free(offsets_heap); + row_log_block_free(index->online_log->head); ut_free(offsets); return(error); } diff --git a/storage/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc index b590a04b3e8..c65c39b7971 100644 --- a/storage/xtradb/row/row0mysql.cc +++ b/storage/xtradb/row/row0mysql.cc @@ -1276,7 +1276,9 @@ row_insert_for_mysql( " newraw is replaced\n" "InnoDB: with raw, and innodb_force_... is removed.\n", stderr); - + if(srv_force_recovery) { + return(DB_READ_ONLY); + } return(DB_ERROR); } @@ -1665,7 +1667,9 @@ row_update_for_mysql( " is replaced\n" "InnoDB: with raw, and innodb_force_... is removed.\n", stderr); - + if(srv_force_recovery) { + return(DB_READ_ONLY); + } return(DB_ERROR); } @@ -3254,7 +3258,6 @@ row_truncate_table_for_mysql( ut_a(trx->dict_operation_lock_mode == 0); /* Prevent foreign key checks etc. while we are truncating the table */ - row_mysql_lock_data_dictionary(trx); ut_ad(mutex_own(&(dict_sys->mutex))); @@ -3318,6 +3321,25 @@ row_truncate_table_for_mysql( goto funct_exit; } + /* Check if memcached plugin is running on this table. if is, we don't + allow truncate this table. */ + if (table->memcached_sync_count != 0) { + ut_print_timestamp(stderr); + fputs(" InnoDB: Cannot truncate table ", stderr); + ut_print_name(stderr, trx, TRUE, table->name); + fputs(" by DROP+CREATE\n" + "InnoDB: because there are memcached operations" + " running on it.\n", + stderr); + err = DB_ERROR; + + goto funct_exit; + } else { + /* We need to set this counter to -1 for blocking + memcached operations. */ + table->memcached_sync_count = DICT_TABLE_IN_DDL; + } + /* Remove all locks except the table-level X lock. */ lock_remove_all_on_table(table, FALSE); @@ -3501,6 +3523,7 @@ next_rec: fts_table.name = table->name; fts_table.id = new_id; + fts_table.flags2 = table->flags2; err = fts_create_common_tables( trx, &fts_table, table->name, TRUE); @@ -3645,6 +3668,12 @@ next_rec: funct_exit: + if (table->memcached_sync_count == DICT_TABLE_IN_DDL) { + /* We need to set the memcached sync back to 0, unblock + memcached operationse. */ + table->memcached_sync_count = 0; + } + row_mysql_unlock_data_dictionary(trx); dict_stats_update(table, DICT_STATS_EMPTY_TABLE); @@ -4716,6 +4745,9 @@ row_rename_table_for_mysql( " is replaced\n" "InnoDB: with raw, and innodb_force_... is removed.\n", stderr); + if(srv_force_recovery) { + err = DB_READ_ONLY; + } goto funct_exit; } else if (row_mysql_is_system_table(new_name)) { @@ -4989,15 +5021,31 @@ row_rename_table_for_mysql( if (err != DB_SUCCESS && (table->space != 0)) { char* orig_name = table->name; + trx_t* trx_bg = trx_allocate_for_background(); + + /* If the first fts_rename fails, the trx would + be rolled back and committed, we can't use it any more, + so we have to start a new background trx here. */ + ut_a(trx_state_eq(trx, TRX_STATE_NOT_STARTED)); + trx_bg->op_info = "Revert the failing rename " + "for fts aux tables"; + trx_bg->dict_operation_lock_mode = RW_X_LATCH; + trx_start_for_ddl(trx_bg, TRX_DICT_OP_TABLE); /* If rename fails and table has its own tablespace, we need to call fts_rename_aux_tables again to revert the ibd file rename, which is not under the control of trx. Also notice the parent table name - in cache is not changed yet. */ + in cache is not changed yet. If the reverting fails, + the ibd data may be left in the new database, which + can be fixed only manually. */ table->name = const_cast(new_name); - fts_rename_aux_tables(table, old_name, trx); + fts_rename_aux_tables(table, old_name, trx_bg); table->name = orig_name; + + trx_bg->dict_operation_lock_mode = 0; + trx_commit_for_mysql(trx_bg); + trx_free_for_background(trx_bg); } } diff --git a/storage/xtradb/row/row0sel.cc b/storage/xtradb/row/row0sel.cc index c68b4de1125..67107c34204 100644 --- a/storage/xtradb/row/row0sel.cc +++ b/storage/xtradb/row/row0sel.cc @@ -5340,25 +5340,40 @@ func_exit: return(value); } -/*******************************************************************//** -Get the last row. -@return current rec or NULL */ +/** Get the maximum and non-delete-marked record in an index. +@param[in] index index tree +@param[in,out] mtr mini-transaction (may be committed and restarted) +@return maximum record, page s-latched in mtr +@retval NULL if there are no records, or if all of them are delete-marked */ static const rec_t* -row_search_autoinc_get_rec( -/*=======================*/ - btr_pcur_t* pcur, /*!< in: the current cursor */ - mtr_t* mtr) /*!< in: mini transaction */ +row_search_get_max_rec( + dict_index_t* index, + mtr_t* mtr) { + btr_pcur_t pcur; + const rec_t* rec; + /* Open at the high/right end (false), and init cursor */ + btr_pcur_open_at_index_side( + false, index, BTR_SEARCH_LEAF, &pcur, true, 0, mtr); + do { - const rec_t* rec = btr_pcur_get_rec(pcur); + const page_t* page; + + page = btr_pcur_get_page(&pcur); + rec = page_find_rec_max_not_deleted(page); if (page_rec_is_user_rec(rec)) { - return(rec); + break; + } else { + rec = NULL; } - } while (btr_pcur_move_to_prev(pcur, mtr)); + btr_pcur_move_before_first_on_page(&pcur); + } while (btr_pcur_move_to_prev(&pcur, mtr)); - return(NULL); + btr_pcur_close(&pcur); + + return(rec); } /*******************************************************************//** @@ -5373,55 +5388,30 @@ row_search_max_autoinc( const char* col_name, /*!< in: name of autoinc column */ ib_uint64_t* value) /*!< out: AUTOINC value read */ { - ulint i; - ulint n_cols; - dict_field_t* dfield = NULL; + dict_field_t* dfield = dict_index_get_nth_field(index, 0); dberr_t error = DB_SUCCESS; - - n_cols = dict_index_get_n_ordering_defined_by_user(index); - - /* Search the index for the AUTOINC column name */ - for (i = 0; i < n_cols; ++i) { - dfield = dict_index_get_nth_field(index, i); - - if (strcmp(col_name, dfield->name) == 0) { - break; - } - } - *value = 0; - /* Must find the AUTOINC column name */ - if (i < n_cols && dfield) { + if (strcmp(col_name, dfield->name) != 0) { + error = DB_RECORD_NOT_FOUND; + } else { mtr_t mtr; - btr_pcur_t pcur; + const rec_t* rec; mtr_start(&mtr); - /* Open at the high/right end (false), and init cursor */ - btr_pcur_open_at_index_side( - false, index, BTR_SEARCH_LEAF, &pcur, true, 0, &mtr); + rec = row_search_get_max_rec(index, &mtr); - if (!page_is_empty(btr_pcur_get_page(&pcur))) { - const rec_t* rec; + if (rec != NULL) { + ibool unsigned_type = ( + dfield->col->prtype & DATA_UNSIGNED); - rec = row_search_autoinc_get_rec(&pcur, &mtr); - - if (rec != NULL) { - ibool unsigned_type = ( - dfield->col->prtype & DATA_UNSIGNED); - - *value = row_search_autoinc_read_column( - index, rec, i, - dfield->col->mtype, unsigned_type); - } + *value = row_search_autoinc_read_column( + index, rec, 0, + dfield->col->mtype, unsigned_type); } - btr_pcur_close(&pcur); - mtr_commit(&mtr); - } else { - error = DB_RECORD_NOT_FOUND; } return(error); diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc index df12fd2b43f..f7f36330d4a 100644 --- a/storage/xtradb/srv/srv0srv.cc +++ b/storage/xtradb/srv/srv0srv.cc @@ -359,6 +359,9 @@ UNIV_INTERN ulong srv_flushing_avg_loops = 30; /* The tid of the cleaner thread */ UNIV_INTERN os_tid_t srv_cleaner_tid; +/* The tid of the LRU manager thread */ +UNIV_INTERN os_tid_t srv_lru_manager_tid; + /* The tids of the purge threads */ UNIV_INTERN os_tid_t srv_purge_tids[SRV_MAX_N_PURGE_THREADS]; @@ -368,7 +371,7 @@ UNIV_INTERN os_tid_t srv_io_tids[SRV_MAX_N_IO_THREADS]; /* The tid of the master thread */ UNIV_INTERN os_tid_t srv_master_tid; -/* The relative scheduling priority of the cleaner thread */ +/* The relative scheduling priority of the cleaner and LRU manager threads */ UNIV_INTERN ulint srv_sched_priority_cleaner = 19; /* The relative scheduling priority of the purge threads */ @@ -510,8 +513,8 @@ counters_pad_end[CACHE_LINE_SIZE] __attribute__((unused)) = {0}; /* Set the following to 0 if you want InnoDB to write messages on stderr on startup/shutdown. */ UNIV_INTERN ibool srv_print_verbose_log = TRUE; -UNIV_INTERN ibool srv_print_innodb_monitor = FALSE; -UNIV_INTERN ibool srv_print_innodb_lock_monitor = FALSE; +UNIV_INTERN my_bool srv_print_innodb_monitor = FALSE; +UNIV_INTERN my_bool srv_print_innodb_lock_monitor = FALSE; UNIV_INTERN ibool srv_print_innodb_tablespace_monitor = FALSE; UNIV_INTERN ibool srv_print_innodb_table_monitor = FALSE; diff --git a/storage/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc index 64d2d4cc896..c1c2f39aaa1 100644 --- a/storage/xtradb/srv/srv0start.cc +++ b/storage/xtradb/srv/srv0start.cc @@ -222,7 +222,8 @@ srv_file_check_mode( /* Note: stat.rw_perm is only valid of files */ - if (stat.type == OS_FILE_TYPE_FILE) { + if (stat.type == OS_FILE_TYPE_FILE + || stat.type == OS_FILE_TYPE_BLOCK) { if (!stat.rw_perm) { ib_logf(IB_LOG_LEVEL_ERROR, @@ -1570,6 +1571,16 @@ innobase_start_or_create_for_mysql(void) # endif /* F_FULLFSYNC */ #endif /* HAVE_DARWIN_THREADS */ + ib_logf(IB_LOG_LEVEL_INFO, + "Using %s to ref count buffer pool pages", +#ifdef PAGE_ATOMIC_REF_COUNT + "atomics" +#else + "mutexes" +#endif /* PAGE_ATOMIC_REF_COUNT */ + ); + + if (sizeof(ulint) != sizeof(void*)) { ut_print_timestamp(stderr); fprintf(stderr, @@ -2729,6 +2740,7 @@ files_checked: if (!srv_read_only_mode) { os_thread_create(buf_flush_page_cleaner_thread, NULL, NULL); } + os_thread_create(buf_flush_lru_manager_thread, NULL, NULL); #ifdef UNIV_DEBUG /* buf_debug_prints = TRUE; */ diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc index 8c4bc087038..f29eba0bec1 100644 --- a/storage/xtradb/trx/trx0trx.cc +++ b/storage/xtradb/trx/trx0trx.cc @@ -738,6 +738,13 @@ trx_resurrect_insert( trx->no = TRX_ID_MAX; } + /* trx_start_low() is not called with resurrect, so need to initialize + start time here.*/ + if (trx->state == TRX_STATE_ACTIVE + || trx->state == TRX_STATE_PREPARED) { + trx->start_time = ut_time(); + } + if (undo->dict_operation) { trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); trx->table_id = undo->table_id; @@ -825,6 +832,13 @@ trx_resurrect_update( trx->no = TRX_ID_MAX; } + /* trx_start_low() is not called with resurrect, so need to initialize + start time here.*/ + if (trx->state == TRX_STATE_ACTIVE + || trx->state == TRX_STATE_PREPARED) { + trx->start_time = ut_time(); + } + if (undo->dict_operation) { trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); trx->table_id = undo->table_id; diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index aba179b154c..96d5ea26a3c 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -5688,7 +5688,7 @@ struct charset_info_st my_charset_utf8_general_mysql500_ci= struct charset_info_st my_charset_utf8_bin= { 83,0,0, /* number */ - MY_CS_COMPILED|MY_CS_BINSORT|MY_CS_UNICODE, /* state */ + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_BINSORT|MY_CS_UNICODE, /* state */ "utf8", /* cs name */ "utf8_bin", /* name */ "", /* comment */