diff --git a/VERSION b/VERSION index 4ed7f1471fd..70bdfecc0c6 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 MYSQL_VERSION_PATCH=28 -MYSQL_VERSION_EXTRA= +MYSQL_VERSION_EXTRA=a diff --git a/client/mysqlshow.c b/client/mysqlshow.c index 5cf2be1160c..323c4282ff4 100644 --- a/client/mysqlshow.c +++ b/client/mysqlshow.c @@ -1,5 +1,6 @@ /* - Copyright (c) 2000, 2011, Oracle and/or its affiliates. + Copyright (c) 2000, 2012, Oracle and/or its affiliates. + Copyright (c) 2010, 2012, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/cmake/mysql_version.cmake b/cmake/mysql_version.cmake index e6b9d3e7edf..33aa33c9e5b 100644 --- a/cmake/mysql_version.cmake +++ b/cmake/mysql_version.cmake @@ -65,7 +65,7 @@ MACRO(GET_MYSQL_VERSION) MARK_AS_ADVANCED(VERSION MYSQL_VERSION_ID MYSQL_BASE_VERSION) SET(CPACK_PACKAGE_VERSION_MAJOR ${MAJOR_VERSION}) SET(CPACK_PACKAGE_VERSION_MINOR ${MINOR_VERSION}) - SET(CPACK_PACKAGE_VERSION_PATCH ${PATCH_VERSION}) + SET(CPACK_PACKAGE_VERSION_PATCH ${PATCH_VERSION}${EXTRA_VERSION}) ENDMACRO() # Get mysql version and other interesting variables diff --git a/extra/perror.c b/extra/perror.c index fbea21f9091..de8a9b8a0c3 100644 --- a/extra/perror.c +++ b/extra/perror.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2011, Oracle and/or its affiliates + Copyright (c) 2000, 2012, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/include/my_base.h b/include/my_base.h index 905e4535360..e072bb7e2b1 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -282,6 +282,9 @@ enum ha_base_keytype { #define HA_USES_BLOCK_SIZE ((uint) 32768) #define HA_SORT_ALLOWS_SAME 512 /* Intern bit when sorting records */ +/* This flag can be used only in KEY::ext_key_flags */ +#define HA_EXT_NOSAME 131072 + /* These flags can be added to key-seg-flag */ #define HA_SPACE_PACK 1 /* Pack space in key-seg */ diff --git a/include/mysql.h b/include/mysql.h index 1fc164f62b2..fa62026b44a 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -47,9 +47,6 @@ extern "C" { #ifndef MYSQL_ABI_CHECK #include #endif -#ifdef __LCC__ -#include /* For windows */ -#endif typedef char my_bool; #if (defined(_WIN32) || defined(_WIN64)) && !defined(__WIN__) #define __WIN__ @@ -61,11 +58,13 @@ typedef char my_bool; #endif #ifndef my_socket_defined -#ifdef __WIN__ -#define my_socket SOCKET +#if defined (_WIN64) +#define my_socket unsigned long long +#elif defined (_WIN32) +#define my_socket unsigned int #else typedef int my_socket; -#endif /* __WIN__ */ +#endif /* _WIN64 */ #endif /* my_socket_defined */ #endif /* _global_h */ diff --git a/include/mysql_com.h b/include/mysql_com.h index 0988d20f97f..6e8a2b23de0 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -57,9 +57,6 @@ #define LOCAL_HOST "localhost" #define LOCAL_HOST_NAMEDPIPE "." -#ifdef _WIN32 -#include -#endif #if defined(__WIN__) && !defined( _CUSTOMCONFIG_) #define MYSQL_NAMEDPIPE "MySQL" diff --git a/include/welcome_copyright_notice.h b/include/welcome_copyright_notice.h index adb7b9f9c20..01139677b7d 100644 --- a/include/welcome_copyright_notice.h +++ b/include/welcome_copyright_notice.h @@ -1,4 +1,5 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. +/* Copyright (c) 2011, 2012, Oracle and/or its affiliates. + Copyright (c) 2011, 2012, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/mysql-test/include/have_innodb.combinations b/mysql-test/include/have_innodb.combinations index 117bf2216a1..93c39fd1a98 100644 --- a/mysql-test/include/have_innodb.combinations +++ b/mysql-test/include/have_innodb.combinations @@ -4,6 +4,9 @@ plugin-load=$HA_INNODB_SO innodb innodb-cmpmem innodb-trx +innodb-buffer-pool-stats +innodb-buffer-page +innodb-buffer-page-lru [xtradb_plugin] ignore-builtin-innodb @@ -11,8 +14,14 @@ plugin-load=$HA_XTRADB_SO innodb innodb-cmpmem innodb-trx +innodb-buffer-pool-stats +innodb-buffer-page +innodb-buffer-page-lru [xtradb] innodb innodb-cmpmem innodb-trx +innodb-buffer-pool-stats +innodb-buffer-page +innodb-buffer-page-lru diff --git a/mysql-test/r/derived_opt.result b/mysql-test/r/derived_opt.result index 11216a32e61..22e2ab8d676 100644 --- a/mysql-test/r/derived_opt.result +++ b/mysql-test/r/derived_opt.result @@ -282,4 +282,74 @@ CREATE TABLE t1 ( i INT ); INSERT INTO t1 VALUES ( (SELECT 1 FROM ( SELECT * FROM t1 ) as a) ); drop table t1; set optimizer_switch=@save_optimizer_switch; +# +# MDEV-3801 Reproducible sub select join crash on 5.3.8 and 5.3.9 +# +CREATE TABLE t1 ( +pk int(10) unsigned NOT NULL AUTO_INCREMENT, +a char(2) DEFAULT NULL, +PRIMARY KEY (pk), +KEY a (a) +) ENGINE=MyISAM; +INSERT INTO t1 (a) +VALUES (NULL),(NULL),(NULL),('AB'),(NULL),('CD'),(NULL),(NULL); +INSERT INTO t1 SELECT NULL, a1.a FROM t1 a1, t1 a2, t1 a3, t1 a4, t1 a5; +CREATE TABLE t2 ( +pk int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t2 SELECT NULL FROM t2 a1, t2 a2, t2 a3, t2 a4, t2 a5; +CREATE TABLE t3 ( +pk int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY +) ENGINE=MyISAM; +INSERT INTO t3 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t3 SELECT NULL FROM t3 a1, t3 a2, t3 a3, t3 a4, t3 a5; +CREATE TABLE t4 ( +a char(2) NOT NULL DEFAULT '', +PRIMARY KEY (a) +) ENGINE=MyISAM; +INSERT INTO t4 VALUES ('CD'); +set @@tmp_table_size=8192; +EXPLAIN +SELECT * FROM t3 AS tx JOIN t2 AS ty ON (tx.pk = ty.pk) +WHERE +tx.pk IN +(SELECT * +FROM (SELECT DISTINCT ta.pk +FROM t3 AS ta +JOIN t2 AS tb ON (ta.pk = tb.pk) +JOIN t1 AS tc ON (tb.pk = tc.pk) +JOIN t4 AS td ON tc.a = td.a) tu) +limit 10; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL distinct_key NULL NULL NULL # +1 PRIMARY tx eq_ref PRIMARY PRIMARY 4 tu.pk # Using index +1 PRIMARY ty eq_ref PRIMARY PRIMARY 4 tu.pk # Using index +2 MATERIALIZED ALL NULL NULL NULL NULL # +3 DERIVED td system PRIMARY NULL NULL NULL # Using temporary +3 DERIVED tc ref PRIMARY,a a 3 const # +3 DERIVED ta eq_ref PRIMARY PRIMARY 4 test.tc.pk # Using index +3 DERIVED tb eq_ref PRIMARY PRIMARY 4 test.tc.pk # Using index; Distinct +SELECT * FROM t3 AS tX JOIN t2 AS tY ON (tX.pk = tY.pk) +WHERE +tX.pk IN +(SELECT * +FROM (SELECT DISTINCT tA.pk +FROM t3 AS tA +JOIN t2 AS tB ON (tA.pk = tB.pk) +JOIN t1 AS tC ON (tB.pk = tC.pk) +JOIN t4 AS tD ON tC.a = tD.a) tU) +limit 10; +pk pk +6 6 +16 16 +24 24 +32 32 +40 40 +48 48 +56 56 +64 64 +72 72 +80 80 +drop table t1, t2, t3, t4; set optimizer_switch=@exit_optimizer_switch; diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 222977e5106..9f942747594 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -2119,6 +2119,17 @@ FROM t2 GROUP BY 1; a DROP TABLE t1, t2; +FLUSH STATUS; +CREATE TABLE t1 (f1 INT, f2 decimal(20,1), f3 blob); +INSERT INTO t1 values(11,NULL,'blob'),(11,NULL,'blob'); +SELECT f3, MIN(f2) FROM t1 GROUP BY f1 LIMIT 1; +f3 MIN(f2) +blob NULL +DROP TABLE t1; +the value below *must* be 1 +show status like 'Created_tmp_disk_tables'; +Variable_name Value +Created_tmp_disk_tables 1 # End of 5.3 tests # # Bug#49771: Incorrect MIN (date) when minimum value is 0000-00-00 diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 85729a3ea87..6bf4cdaeeba 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1684,6 +1684,12 @@ SELECT length(CAST(b AS CHAR)) FROM ubig; length(CAST(b AS CHAR)) 20 DROP TABLE ubig; +select 1 from information_schema.tables where table_schema=repeat('a', 2000); +1 +grant usage on *.* to mysqltest_1@localhost; +select 1 from information_schema.tables where table_schema=repeat('a', 2000); +1 +drop user mysqltest_1@localhost; End of 5.1 tests. # # Additional test for WL#3726 "DDL locking for all metadata objects" diff --git a/mysql-test/r/innodb_ext_key.result b/mysql-test/r/innodb_ext_key.result index d2fb29a023c..4e441245a39 100644 --- a/mysql-test/r/innodb_ext_key.result +++ b/mysql-test/r/innodb_ext_key.result @@ -613,6 +613,26 @@ Handler_read_prev 0 Handler_read_rnd 0 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 +# +# Bug mdev-3851: ref access used instead of expected eq_ref access +# when extended_keys=on +# +create table t0 (a int); +insert into t0 values (1), (2), (3), (4), (5); +create index i_p_size on part(p_size); +set optimizer_switch='extended_keys=on'; +explain +select * from t0, part ignore index (primary) +where p_partkey=t0.a and p_size=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 5 Using where +1 SIMPLE part eq_ref i_p_size i_p_size 9 const,dbt3_s001.t0.a 1 +select * from t0, part ignore index (primary) +where p_partkey=t0.a and p_size=1; +a p_partkey p_name p_mfgr p_brand p_type p_size p_container p_retailprice p_comment +2 2 blush rosy metallic lemon navajo Manufacturer#1 Brand#13 LARGE BRUSHED BRASS 1 LG CASE 902 final platelets hang f +drop table t0; +drop index i_p_size on part; DROP DATABASE dbt3_s001; use test; # @@ -724,5 +744,33 @@ SELECT * FROM t1, t2 WHERE b=a; a b set optimizer_switch=@save_optimizer_switch; DROP TABLE t1,t2; +# +# Bug mdev-3888: INSERT with UPDATE on duplicate keys +# with extended_keys=on +# +CREATE TABLE t1 ( +c1 bigint(20) unsigned NOT NULL AUTO_INCREMENT, +c2 bigint(20) unsigned NOT NULL, +c3 bigint(20) unsigned NOT NULL, +c4 varchar(128) DEFAULT NULL, +PRIMARY KEY (c1), +UNIQUE KEY uq (c2,c3), +KEY c3 (c3), +KEY c4 (c4) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; +set @save_optimizer_switch=@@optimizer_switch; +set session optimizer_switch='extended_keys=off'; +INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') +ON DUPLICATE KEY UPDATE c4 = VALUES(c4); +INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') +ON DUPLICATE KEY UPDATE c4 = VALUES(c4); +DELETE FROM t1; +set session optimizer_switch='extended_keys=on'; +INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') +ON DUPLICATE KEY UPDATE c4 = VALUES(c4); +INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') +ON DUPLICATE KEY UPDATE c4 = VALUES(c4); +set optimizer_switch=@save_optimizer_switch; +DROP TABLE t1; set optimizer_switch=@save_ext_key_optimizer_switch; SET SESSION STORAGE_ENGINE=DEFAULT; diff --git a/mysql-test/r/openssl_1.result b/mysql-test/r/openssl_1.result index b86925e0eb8..76b8e887d89 100644 --- a/mysql-test/r/openssl_1.result +++ b/mysql-test/r/openssl_1.result @@ -83,7 +83,7 @@ Ssl_cipher AES128-SHA SHOW STATUS LIKE 'Ssl_cipher'; Variable_name Value Ssl_cipher AES128-SHA -mysqltest: Could not open connection 'default': 2026 SSL connection error: SSL_CTX_new failed +mysqltest: Could not open connection 'default': 2026 SSL connection error: Failed to set ciphers to use CREATE TABLE t1(a int); INSERT INTO t1 VALUES (1), (2); diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 53fed519a15..94e7d5e757a 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -1945,3 +1945,79 @@ f0 f1 f2 set sort_buffer_size= @save_sort_buffer_size; DROP TABLE t1; End of 5.3 tests +# +# Bug 54599: discarded fast range scan for query with +# GROUP BY + ORDER BY + LIMIT +# +create table t0 (a int); +insert into t0 values (0), (1), (2), (3), (4), (5), (6), (7), (8), (9); +create table t1 (a int, b int, index idx1(a,b), index idx2(b,a)); +insert into t1 +select 1000*s4.a+100*s3.a+10*s2.a + s1.a, 1000*s4.a+100*s3.a+10*s2.a+s1.a +from t0 s1, t0 s2, t0 s3, t0 s4; +analyze table t1; +explain +select b, count(*) num_cnt from t1 +where a > 9750 group by b order by num_cnt; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx1 idx1 5 NULL 502 Using where; Using index; Using temporary; Using filesort +flush status; +select b, count(*) num_cnt from t1 +where a > 9750 group by b order by num_cnt; +show status like '%Handler_read%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 250 +Handler_read_last 0 +Handler_read_next 249 +Handler_read_prev 0 +Handler_read_rnd 249 +Handler_read_rnd_deleted 0 +Handler_read_rnd_next 250 +explain +select b, count(*) num_cnt from t1 +where a > 9750 group by b order by num_cnt limit 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx1 idx1 5 NULL 502 Using where; Using index; Using temporary; Using filesort +flush status; +select b, count(*) num_cnt from t1 +where a > 9750 group by b order by num_cnt limit 1; +show status like '%Handler_read%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 250 +Handler_read_last 0 +Handler_read_next 249 +Handler_read_prev 0 +Handler_read_rnd 1 +Handler_read_rnd_deleted 0 +Handler_read_rnd_next 250 +drop table t0, t1; +# +# LP bug #1002508 : the number of expected rows to be examined is off +# (bug #13528826) +# +CREATE TABLE t1(a int PRIMARY KEY, b int) ENGINE=myisam; +INSERT INTO t1 VALUES +(5, 10), (2, 70), (7, 80), (6, 20), (1, 50), (9, 40), (8, 30), (3, 60); +CREATE TABLE t2 (p int, a int, INDEX i_a(a)) ENGINE=myisam; +INSERT INTO t2 VALUES +(103, 7), (109, 3), (102, 3), (108, 1), (106, 3), +(107, 7), (105, 1), (101, 3), (100, 7), (110, 1); +EXPLAIN +SELECT t1.a FROM t1 LEFT JOIN t2 ON t1.a=t2.a ORDER BY t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 8 Using index +1 SIMPLE t2 ref i_a i_a 5 test.t1.a 2 Using index +EXPLAIN +SELECT t1.a FROM t1 LEFT JOIN t2 ON t1.a=t2.a ORDER BY t1.a LIMIT 8; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 Using index +1 SIMPLE t2 ref i_a i_a 5 test.t1.a 2 Using index +EXPLAIN +SELECT t1.a FROM t1 LEFT JOIN t2 ON t1.a=t2.a ORDER BY t1.a LIMIT 100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 8 Using index +1 SIMPLE t2 ref i_a i_a 5 test.t1.a 2 Using index +DROP TABLE t1,t2; +End of 5.5 tests diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 40586b8d54b..86425825601 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -2394,6 +2394,12 @@ HAVING b > geomfromtext("") ); 1 DROP TABLE t1; + +MDEV-612 Valgrind error in ha_maria::check_if_incompatible_data + +CREATE TABLE t1 (a INT, b INT, KEY(a)) ENGINE=Aria PARTITION BY KEY(a) PARTITIONS 2; +ALTER TABLE t1 ADD KEY (b); +drop table t1; End of 5.1 tests # # BUG#55385: UPDATE statement throws an error, but still updates diff --git a/mysql-test/r/range_vs_index_merge.result b/mysql-test/r/range_vs_index_merge.result index faaa6d2429e..cc8a345a2ff 100644 --- a/mysql-test/r/range_vs_index_merge.result +++ b/mysql-test/r/range_vs_index_merge.result @@ -1221,6 +1221,153 @@ Lugansk UKR 469000 Seattle USA 563374 Caracas VEN 1975294 set optimizer_switch=@save_optimizer_switch; +# +# Bug mdev-585: range vs index-merge with ORDER BY ... LIMIT n +# (LP bug #637962) +# +DROP INDEX CountryPopulation ON City; +DROP INDEX CountryName ON City; +DROP INDEX CityName on City; +CREATE INDEX Name ON City(Name); +CREATE INDEX Population ON City(Population); +EXPLAIN +SELECT * FROM City +WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) +AND (Population >= 100000 AND Population < 120000); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE City index_merge Country,Name,Population Name,Country 35,3 NULL # Using sort_union(Name,Country); Using where +FLUSH STATUS; +SELECT * FROM City +WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) +AND (Population >= 100000 AND Population < 120000); +ID Name Country Population +384 Cabo Frio BRA 119503 +387 Camaragibe BRA 118968 +403 Catanduva BRA 107761 +412 Cachoeirinha BRA 103240 +508 Watford GBR 113080 +509 Ipswich GBR 114000 +510 Slough GBR 112000 +511 Exeter GBR 111000 +512 Cheltenham GBR 106000 +513 Gloucester GBR 107000 +514 Saint Helens GBR 106293 +515 Sutton Coldfield GBR 106001 +516 York GBR 104425 +517 Oldham GBR 103931 +518 Basildon GBR 100924 +519 Worthing GBR 100000 +635 Mallawi EGY 119283 +636 Bilbays EGY 113608 +637 Mit Ghamr EGY 101801 +638 al-Arish EGY 100447 +701 Tarragona ESP 113016 +702 Lleida (Lérida) ESP 112207 +703 Jaén ESP 109247 +704 Ourense (Orense) ESP 109120 +705 Mataró ESP 104095 +706 Algeciras ESP 103106 +707 Marbella ESP 101144 +759 Gonder ETH 112249 +869 Cabuyao PHL 106630 +870 Calapan PHL 105910 +873 Cauayan PHL 103952 +903 Serekunda GMB 102600 +909 Sohumi GEO 111700 +913 Tema GHA 109975 +914 Sekondi-Takoradi GHA 103653 +924 Villa Nueva GTM 101295 +1844 Cape Breton CAN 114733 +1847 Cambridge CAN 109186 +2406 Herakleion GRC 116178 +2407 Kallithea GRC 114233 +2408 Larisa GRC 113090 +2908 Cajamarca PER 108009 +3002 Besançon FRA 117733 +3003 Caen FRA 113987 +3004 Orléans FRA 113126 +3005 Mulhouse FRA 110359 +3006 Rouen FRA 106592 +3007 Boulogne-Billancourt FRA 106367 +3008 Perpignan FRA 105115 +3009 Nancy FRA 103605 +3411 Ceyhan TUR 102412 +3567 Carúpano VEN 119639 +3568 Catia La Mar VEN 117012 +3571 Calabozo VEN 107146 +3786 Cam Ranh VNM 114041 +3792 Tartu EST 101246 +4002 Carrollton USA 109576 +4027 Cape Coral USA 102286 +4032 Cambridge USA 101355 +SHOW STATUS LIKE 'Handler_read_%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 2 +Handler_read_last 0 +Handler_read_next 385 +Handler_read_prev 0 +Handler_read_rnd 377 +Handler_read_rnd_deleted 0 +Handler_read_rnd_next 0 +EXPLAIN +SELECT * FROM City +WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) +AND (Population >= 100000 AND Population < 120000) +ORDER BY Population LIMIT 5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE City range Country,Name,Population Population 4 NULL # Using where +FLUSH STATUS; +SELECT * FROM City +WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) +AND (Population >= 100000 AND Population < 120000) +ORDER BY Population LIMIT 5; +ID Name Country Population +519 Worthing GBR 100000 +638 al-Arish EGY 100447 +518 Basildon GBR 100924 +707 Marbella ESP 101144 +3792 Tartu EST 101246 +SHOW STATUS LIKE 'Handler_read_%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 1 +Handler_read_last 0 +Handler_read_next 59 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_deleted 0 +Handler_read_rnd_next 0 +set optimizer_switch='index_merge=off'; +EXPLAIN +SELECT * FROM City +WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) +AND (Population >= 100000 AND Population < 120000) +ORDER BY Population LIMIT 5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE City range Country,Name,Population Population 4 NULL # Using index condition; Using where +FLUSH STATUS; +SELECT * FROM City +WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) +AND (Population >= 100000 AND Population < 120000) +ORDER BY Population LIMIT 5; +ID Name Country Population +519 Worthing GBR 100000 +638 al-Arish EGY 100447 +518 Basildon GBR 100924 +707 Marbella ESP 101144 +3792 Tartu EST 101246 +SHOW STATUS LIKE 'Handler_read_%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 1 +Handler_read_last 0 +Handler_read_next 59 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_deleted 0 +Handler_read_rnd_next 0 +set optimizer_switch=@save_optimizer_switch; DROP DATABASE world; use test; CREATE TABLE t1 ( diff --git a/mysql-test/r/range_vs_index_merge_innodb,innodb_plugin.rdiff b/mysql-test/r/range_vs_index_merge_innodb,innodb_plugin.rdiff index 5913434caae..ecae2c809c1 100644 --- a/mysql-test/r/range_vs_index_merge_innodb,innodb_plugin.rdiff +++ b/mysql-test/r/range_vs_index_merge_innodb,innodb_plugin.rdiff @@ -1,5 +1,5 @@ ---- r/range_vs_index_merge_innodb.result 2012-03-24 17:12:02.124422000 +0100 -+++ r/range_vs_index_merge_innodb,innodb_plugin.reject 2012-03-24 18:00:13.647902620 +0100 +--- ./r/range_vs_index_merge_innodb.result 2012-11-21 19:35:14.000000000 +0100 ++++ ./r/range_vs_index_merge_innodb,innodb_plugin.reject 2012-11-21 20:56:00.000000000 +0100 @@ -50,14 +50,14 @@ WHERE (Population >= 100000 OR Name LIKE 'P%') AND Country='CAN' OR (Population < 100000 OR Name Like 'T%') AND Country='ARG'; @@ -269,3 +269,12 @@ SELECT Name, Country, Population FROM City WHERE (Name='Manila' AND Country='PHL') OR (Name='Addis Abeba' AND Country='ETH') OR +@@ -1346,7 +1346,7 @@ + AND (Population >= 100000 AND Population < 120000) + ORDER BY Population LIMIT 5; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE City range Country,Name,Population Population 4 NULL # Using index condition; Using where ++1 SIMPLE City range Country,Name,Population Population 4 NULL # Using where + FLUSH STATUS; + SELECT * FROM City + WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) diff --git a/mysql-test/r/range_vs_index_merge_innodb.result b/mysql-test/r/range_vs_index_merge_innodb.result index df3a2af0753..67e341192da 100644 --- a/mysql-test/r/range_vs_index_merge_innodb.result +++ b/mysql-test/r/range_vs_index_merge_innodb.result @@ -1222,6 +1222,153 @@ Lugansk UKR 469000 Seattle USA 563374 Caracas VEN 1975294 set optimizer_switch=@save_optimizer_switch; +# +# Bug mdev-585: range vs index-merge with ORDER BY ... LIMIT n +# (LP bug #637962) +# +DROP INDEX CountryPopulation ON City; +DROP INDEX CountryName ON City; +DROP INDEX CityName on City; +CREATE INDEX Name ON City(Name); +CREATE INDEX Population ON City(Population); +EXPLAIN +SELECT * FROM City +WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) +AND (Population >= 100000 AND Population < 120000); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE City index_merge Country,Name,Population Name,Country 35,3 NULL # Using sort_union(Name,Country); Using where +FLUSH STATUS; +SELECT * FROM City +WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) +AND (Population >= 100000 AND Population < 120000); +ID Name Country Population +384 Cabo Frio BRA 119503 +387 Camaragibe BRA 118968 +403 Catanduva BRA 107761 +412 Cachoeirinha BRA 103240 +508 Watford GBR 113080 +509 Ipswich GBR 114000 +510 Slough GBR 112000 +511 Exeter GBR 111000 +512 Cheltenham GBR 106000 +513 Gloucester GBR 107000 +514 Saint Helens GBR 106293 +515 Sutton Coldfield GBR 106001 +516 York GBR 104425 +517 Oldham GBR 103931 +518 Basildon GBR 100924 +519 Worthing GBR 100000 +635 Mallawi EGY 119283 +636 Bilbays EGY 113608 +637 Mit Ghamr EGY 101801 +638 al-Arish EGY 100447 +701 Tarragona ESP 113016 +702 Lleida (Lérida) ESP 112207 +703 Jaén ESP 109247 +704 Ourense (Orense) ESP 109120 +705 Mataró ESP 104095 +706 Algeciras ESP 103106 +707 Marbella ESP 101144 +759 Gonder ETH 112249 +869 Cabuyao PHL 106630 +870 Calapan PHL 105910 +873 Cauayan PHL 103952 +903 Serekunda GMB 102600 +909 Sohumi GEO 111700 +913 Tema GHA 109975 +914 Sekondi-Takoradi GHA 103653 +924 Villa Nueva GTM 101295 +1844 Cape Breton CAN 114733 +1847 Cambridge CAN 109186 +2406 Herakleion GRC 116178 +2407 Kallithea GRC 114233 +2408 Larisa GRC 113090 +2908 Cajamarca PER 108009 +3002 Besançon FRA 117733 +3003 Caen FRA 113987 +3004 Orléans FRA 113126 +3005 Mulhouse FRA 110359 +3006 Rouen FRA 106592 +3007 Boulogne-Billancourt FRA 106367 +3008 Perpignan FRA 105115 +3009 Nancy FRA 103605 +3411 Ceyhan TUR 102412 +3567 Carúpano VEN 119639 +3568 Catia La Mar VEN 117012 +3571 Calabozo VEN 107146 +3786 Cam Ranh VNM 114041 +3792 Tartu EST 101246 +4002 Carrollton USA 109576 +4027 Cape Coral USA 102286 +4032 Cambridge USA 101355 +SHOW STATUS LIKE 'Handler_read_%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 2 +Handler_read_last 0 +Handler_read_next 385 +Handler_read_prev 0 +Handler_read_rnd 377 +Handler_read_rnd_deleted 0 +Handler_read_rnd_next 0 +EXPLAIN +SELECT * FROM City +WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) +AND (Population >= 100000 AND Population < 120000) +ORDER BY Population LIMIT 5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE City range Country,Name,Population Population 4 NULL # Using where +FLUSH STATUS; +SELECT * FROM City +WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) +AND (Population >= 100000 AND Population < 120000) +ORDER BY Population LIMIT 5; +ID Name Country Population +519 Worthing GBR 100000 +638 al-Arish EGY 100447 +518 Basildon GBR 100924 +707 Marbella ESP 101144 +3792 Tartu EST 101246 +SHOW STATUS LIKE 'Handler_read_%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 1 +Handler_read_last 0 +Handler_read_next 59 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_deleted 0 +Handler_read_rnd_next 0 +set optimizer_switch='index_merge=off'; +EXPLAIN +SELECT * FROM City +WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) +AND (Population >= 100000 AND Population < 120000) +ORDER BY Population LIMIT 5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE City range Country,Name,Population Population 4 NULL # Using index condition; Using where +FLUSH STATUS; +SELECT * FROM City +WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) +AND (Population >= 100000 AND Population < 120000) +ORDER BY Population LIMIT 5; +ID Name Country Population +519 Worthing GBR 100000 +638 al-Arish EGY 100447 +518 Basildon GBR 100924 +707 Marbella ESP 101144 +3792 Tartu EST 101246 +SHOW STATUS LIKE 'Handler_read_%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 1 +Handler_read_last 0 +Handler_read_next 59 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_deleted 0 +Handler_read_rnd_next 0 +set optimizer_switch=@save_optimizer_switch; DROP DATABASE world; use test; CREATE TABLE t1 ( diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index a4bad836d1f..14347e9b899 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -6060,6 +6060,116 @@ WHERE (col_varchar_nokey, 'x') IN col_int_nokey 1 DROP TABLE ot,it1,it2; +# +# MDEV-746 +# Bug#13651009 WRONG RESULT FROM DERIVED TABLE IF THE SUBQUERY +# HAS AN EMPTY RESULT +# +CREATE TABLE t1 ( +pk int NOT NULL, +col_int_nokey int NOT NULL, +col_int_key int NOT NULL, +col_time_key time NOT NULL, +col_varchar_key varchar(1) NOT NULL, +col_varchar_nokey varchar(1) NOT NULL, +PRIMARY KEY (pk), +KEY col_int_key (col_int_key), +KEY col_time_key (col_time_key), +KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; +CREATE TABLE t2 ( +pk int NOT NULL AUTO_INCREMENT, +col_int_nokey int NOT NULL, +col_int_key int NOT NULL, +col_time_key time NOT NULL, +col_varchar_key varchar(1) NOT NULL, +col_varchar_nokey varchar(1) NOT NULL, +PRIMARY KEY (pk), +KEY col_int_key (col_int_key), +KEY col_time_key (col_time_key), +KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1,4,4,'00:00:00','b','b'); +SET @var2:=4, @var3:=8; + +Testcase without inner subquery +EXPLAIN SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3; +@var3:=12 pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +SELECT @var3; +@var3 +8 +EXPLAIN SELECT * FROM ( SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3 ) AS alias3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE system NULL NULL NULL NULL 0 const row not found +2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table +SELECT * FROM ( SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3 ) AS alias3; +@var3:=12 pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +SELECT @var3; +@var3 +8 + +Testcase with inner subquery; crashed WL#6095 +SET @var3=8; +EXPLAIN SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1 +SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)); +pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +EXPLAIN SELECT * FROM ( SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)) ) AS alias3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1 +SELECT * FROM ( SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)) ) AS alias3; +pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +DROP TABLE t1,t2; End of 5.2 tests # # BUG#779885: Crash in eliminate_item_equal with materialization=on in @@ -6860,7 +6970,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 1 Using where; Using index +2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # @@ -6894,6 +7004,6 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 1 Using where; Using index +2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; diff --git a/mysql-test/r/subselect2.result b/mysql-test/r/subselect2.result index 7eff7f949a8..4fd303dfd44 100644 --- a/mysql-test/r/subselect2.result +++ b/mysql-test/r/subselect2.result @@ -180,6 +180,32 @@ SET optimizer_switch=@tmp_optimizer_switch; DROP VIEW v1; DROP TABLE t1,t2,t3; # +# MDEV-536: LP:1050806 - different result for a query using subquery +# +DROP TABLE IF EXISTS `t1`; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE `t1` ( +`node_uid` bigint(20) unsigned DEFAULT NULL, +`date` datetime DEFAULT NULL, +`mirror_date` datetime DEFAULT NULL, +KEY `date` (`date`) +) ENGINE=MyISAM; +INSERT INTO `t1` VALUES (2085,'2012-01-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2084,'2012-02-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2088,'2012-03-01 00:00:00','2013-01-01 00:00:00'); +SELECT * FROM ( +SELECT node_uid, date, mirror_date, @result := 0 AS result +FROM t1 +WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) +ORDER BY mirror_date ASC +) AS calculated_result; +node_uid date mirror_date result +2085 2012-01-01 00:00:00 2013-01-01 00:00:00 0 +2084 2012-02-01 00:00:00 2013-01-01 00:00:00 0 +DROP TABLE t1; +# # MDEV-567: Wrong result from a query with correlated subquery if ICP is allowed # CREATE TABLE t1 (a int, b int, INDEX idx(a)); @@ -197,5 +223,76 @@ a b 1 0 1 1 1 3 -DROP TABLE t1, t2, t3; +set @tmp_mdev567=@@optimizer_switch; +set optimizer_switch='mrr=off'; +SELECT * FROM t3 +WHERE a = (SELECT COUNT(DISTINCT t2.b) FROM t1, t2 +WHERE t1.a = t2.a AND t2.a BETWEEN 7 AND 9 +AND t3.b = t1.b +GROUP BY t1.b); +a b +1 0 +1 1 +1 3 +DROP TABLE t1,t2,t3; +set optimizer_switch=@tmp_mdev567; +# +# MDEV-614, also MDEV-536, also LP:1050806: +# different result for a query using subquery between 5.5.25 and 5.5.27 +# +CREATE TABLE `t1` ( +`node_uid` bigint(20) unsigned DEFAULT NULL, +`date` datetime DEFAULT NULL, +`mirror_date` datetime DEFAULT NULL, +KEY `date` (`date`) +) ENGINE=MyISAM; +INSERT INTO `t1` VALUES (2085,'2012-01-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2084,'2012-02-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2088,'2012-03-01 00:00:00','2013-01-01 00:00:00'); +explain +SELECT * FROM ( +SELECT node_uid, date, mirror_date, @result := 0 AS result +FROM t1 +WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) +ORDER BY mirror_date ASC +) AS calculated_result; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE ALL NULL NULL NULL NULL 2 +2 DERIVED t1 range date date 9 NULL 2 Using index condition; Using where; Rowid-ordered scan; Using filesort +SELECT * FROM ( +SELECT node_uid, date, mirror_date, @result := 0 AS result +FROM t1 +WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) +ORDER BY mirror_date ASC +) AS calculated_result; +node_uid date mirror_date result +2085 2012-01-01 00:00:00 2013-01-01 00:00:00 0 +2084 2012-02-01 00:00:00 2013-01-01 00:00:00 0 +set @tmp_mdev614=@@optimizer_switch; +set optimizer_switch='mrr=off'; +explain +SELECT * FROM ( +SELECT node_uid, date, mirror_date, @result := 0 AS result +FROM t1 +WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) +ORDER BY mirror_date ASC +) AS calculated_result; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE ALL NULL NULL NULL NULL 2 +2 DERIVED t1 range date date 9 NULL 2 Using index condition; Using where; Using filesort +SELECT * FROM ( +SELECT node_uid, date, mirror_date, @result := 0 AS result +FROM t1 +WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) +ORDER BY mirror_date ASC +) AS calculated_result; +node_uid date mirror_date result +2085 2012-01-01 00:00:00 2013-01-01 00:00:00 0 +2084 2012-02-01 00:00:00 2013-01-01 00:00:00 0 +set optimizer_switch=@tmp_mdev614; +DROP TABLE t1; set optimizer_switch=@subselect2_test_tmp; diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index cb9847a0d99..c307a68f64d 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -6059,6 +6059,116 @@ WHERE (col_varchar_nokey, 'x') IN col_int_nokey 1 DROP TABLE ot,it1,it2; +# +# MDEV-746 +# Bug#13651009 WRONG RESULT FROM DERIVED TABLE IF THE SUBQUERY +# HAS AN EMPTY RESULT +# +CREATE TABLE t1 ( +pk int NOT NULL, +col_int_nokey int NOT NULL, +col_int_key int NOT NULL, +col_time_key time NOT NULL, +col_varchar_key varchar(1) NOT NULL, +col_varchar_nokey varchar(1) NOT NULL, +PRIMARY KEY (pk), +KEY col_int_key (col_int_key), +KEY col_time_key (col_time_key), +KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; +CREATE TABLE t2 ( +pk int NOT NULL AUTO_INCREMENT, +col_int_nokey int NOT NULL, +col_int_key int NOT NULL, +col_time_key time NOT NULL, +col_varchar_key varchar(1) NOT NULL, +col_varchar_nokey varchar(1) NOT NULL, +PRIMARY KEY (pk), +KEY col_int_key (col_int_key), +KEY col_time_key (col_time_key), +KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1,4,4,'00:00:00','b','b'); +SET @var2:=4, @var3:=8; + +Testcase without inner subquery +EXPLAIN SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3; +@var3:=12 pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +SELECT @var3; +@var3 +8 +EXPLAIN SELECT * FROM ( SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3 ) AS alias3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE system NULL NULL NULL NULL 0 const row not found +2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table +SELECT * FROM ( SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3 ) AS alias3; +@var3:=12 pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +SELECT @var3; +@var3 +8 + +Testcase with inner subquery; crashed WL#6095 +SET @var3=8; +EXPLAIN SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1 +SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)); +pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +EXPLAIN SELECT * FROM ( SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)) ) AS alias3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1 +SELECT * FROM ( SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)) ) AS alias3; +pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +DROP TABLE t1,t2; End of 5.2 tests # # BUG#779885: Crash in eliminate_item_equal with materialization=on in @@ -6858,7 +6968,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 1 Using where; Using index +2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # @@ -6891,7 +7001,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 1 Using where; Using index +2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; set optimizer_switch=default; diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index 63eeb816b38..d1590b0df51 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -6055,6 +6055,116 @@ WHERE (col_varchar_nokey, 'x') IN col_int_nokey 1 DROP TABLE ot,it1,it2; +# +# MDEV-746 +# Bug#13651009 WRONG RESULT FROM DERIVED TABLE IF THE SUBQUERY +# HAS AN EMPTY RESULT +# +CREATE TABLE t1 ( +pk int NOT NULL, +col_int_nokey int NOT NULL, +col_int_key int NOT NULL, +col_time_key time NOT NULL, +col_varchar_key varchar(1) NOT NULL, +col_varchar_nokey varchar(1) NOT NULL, +PRIMARY KEY (pk), +KEY col_int_key (col_int_key), +KEY col_time_key (col_time_key), +KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; +CREATE TABLE t2 ( +pk int NOT NULL AUTO_INCREMENT, +col_int_nokey int NOT NULL, +col_int_key int NOT NULL, +col_time_key time NOT NULL, +col_varchar_key varchar(1) NOT NULL, +col_varchar_nokey varchar(1) NOT NULL, +PRIMARY KEY (pk), +KEY col_int_key (col_int_key), +KEY col_time_key (col_time_key), +KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1,4,4,'00:00:00','b','b'); +SET @var2:=4, @var3:=8; + +Testcase without inner subquery +EXPLAIN SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3; +@var3:=12 pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +SELECT @var3; +@var3 +8 +EXPLAIN SELECT * FROM ( SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3 ) AS alias3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE system NULL NULL NULL NULL 0 const row not found +2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table +SELECT * FROM ( SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3 ) AS alias3; +@var3:=12 pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +SELECT @var3; +@var3 +8 + +Testcase with inner subquery; crashed WL#6095 +SET @var3=8; +EXPLAIN SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1 +SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)); +pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +EXPLAIN SELECT * FROM ( SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)) ) AS alias3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1 +SELECT * FROM ( SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)) ) AS alias3; +pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +DROP TABLE t1,t2; End of 5.2 tests # # BUG#779885: Crash in eliminate_item_equal with materialization=on in @@ -6855,7 +6965,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 1 Using where; Using index +2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # @@ -6889,7 +6999,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 1 Using where; Using index +2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; set @optimizer_switch_for_subselect_test=null; diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index 6fd21f8d0b0..b6b5572815a 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -6066,6 +6066,116 @@ WHERE (col_varchar_nokey, 'x') IN col_int_nokey 1 DROP TABLE ot,it1,it2; +# +# MDEV-746 +# Bug#13651009 WRONG RESULT FROM DERIVED TABLE IF THE SUBQUERY +# HAS AN EMPTY RESULT +# +CREATE TABLE t1 ( +pk int NOT NULL, +col_int_nokey int NOT NULL, +col_int_key int NOT NULL, +col_time_key time NOT NULL, +col_varchar_key varchar(1) NOT NULL, +col_varchar_nokey varchar(1) NOT NULL, +PRIMARY KEY (pk), +KEY col_int_key (col_int_key), +KEY col_time_key (col_time_key), +KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; +CREATE TABLE t2 ( +pk int NOT NULL AUTO_INCREMENT, +col_int_nokey int NOT NULL, +col_int_key int NOT NULL, +col_time_key time NOT NULL, +col_varchar_key varchar(1) NOT NULL, +col_varchar_nokey varchar(1) NOT NULL, +PRIMARY KEY (pk), +KEY col_int_key (col_int_key), +KEY col_time_key (col_time_key), +KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1,4,4,'00:00:00','b','b'); +SET @var2:=4, @var3:=8; + +Testcase without inner subquery +EXPLAIN SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3; +@var3:=12 pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +SELECT @var3; +@var3 +8 +EXPLAIN SELECT * FROM ( SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3 ) AS alias3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE system NULL NULL NULL NULL 0 const row not found +2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table +SELECT * FROM ( SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3 ) AS alias3; +@var3:=12 pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +SELECT @var3; +@var3 +8 + +Testcase with inner subquery; crashed WL#6095 +SET @var3=8; +EXPLAIN SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1 +SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)); +pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +EXPLAIN SELECT * FROM ( SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)) ) AS alias3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1 +SELECT * FROM ( SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)) ) AS alias3; +pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +DROP TABLE t1,t2; End of 5.2 tests # # BUG#779885: Crash in eliminate_item_equal with materialization=on in @@ -6866,7 +6976,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 1 Using where; Using index +2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # @@ -6900,7 +7010,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 1 Using where; Using index +2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; set optimizer_switch=default; diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index b924a18ca8f..34cdb17e23e 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -6055,6 +6055,116 @@ WHERE (col_varchar_nokey, 'x') IN col_int_nokey 1 DROP TABLE ot,it1,it2; +# +# MDEV-746 +# Bug#13651009 WRONG RESULT FROM DERIVED TABLE IF THE SUBQUERY +# HAS AN EMPTY RESULT +# +CREATE TABLE t1 ( +pk int NOT NULL, +col_int_nokey int NOT NULL, +col_int_key int NOT NULL, +col_time_key time NOT NULL, +col_varchar_key varchar(1) NOT NULL, +col_varchar_nokey varchar(1) NOT NULL, +PRIMARY KEY (pk), +KEY col_int_key (col_int_key), +KEY col_time_key (col_time_key), +KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; +CREATE TABLE t2 ( +pk int NOT NULL AUTO_INCREMENT, +col_int_nokey int NOT NULL, +col_int_key int NOT NULL, +col_time_key time NOT NULL, +col_varchar_key varchar(1) NOT NULL, +col_varchar_nokey varchar(1) NOT NULL, +PRIMARY KEY (pk), +KEY col_int_key (col_int_key), +KEY col_time_key (col_time_key), +KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1,4,4,'00:00:00','b','b'); +SET @var2:=4, @var3:=8; + +Testcase without inner subquery +EXPLAIN SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3; +@var3:=12 pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +SELECT @var3; +@var3 +8 +EXPLAIN SELECT * FROM ( SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3 ) AS alias3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE system NULL NULL NULL NULL 0 const row not found +2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table +SELECT * FROM ( SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3 ) AS alias3; +@var3:=12 pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +SELECT @var3; +@var3 +8 + +Testcase with inner subquery; crashed WL#6095 +SET @var3=8; +EXPLAIN SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1 +SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)); +pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +EXPLAIN SELECT * FROM ( SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)) ) AS alias3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1 +SELECT * FROM ( SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)) ) AS alias3; +pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +DROP TABLE t1,t2; End of 5.2 tests # # BUG#779885: Crash in eliminate_item_equal with materialization=on in @@ -6855,7 +6965,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 1 Using where; Using index +2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; # @@ -6889,7 +6999,7 @@ INSERT INTO t2 VALUES (45),(17),(20); EXPLAIN SELECT * FROM t1 WHERE EXISTS ( SELECT a FROM t1, t2 WHERE b = a GROUP BY a HAVING a <> 1 ) ; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY t1 index a a 5 NULL 1 Using where; Using index +2 SUBQUERY t1 index a a 5 NULL 2 Using where; Using index 2 SUBQUERY t2 ref b b 5 test.t1.a 2 Using index DROP TABLE t1,t2; set @optimizer_switch_for_subselect_test=null; diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index e98dda46061..9c4fd02fcdd 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -498,4 +498,36 @@ DROP TABLE t1; # SET @bug12408412=1; SELECT GROUP_CONCAT(@bug12408412 ORDER BY 1) INTO @bug12408412; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (0); +SELECT DISTINCT POW(COUNT(*), @a:=(SELECT 1 FROM t1 LEFT JOIN t1 AS t2 ON @a)) +AS b FROM t1 GROUP BY a; +b +1 +SELECT @a; +@a +1 +DROP TABLE t1; +CREATE TABLE t1(f1 INT, f2 INT); +INSERT INTO t1 VALUES (1,2),(2,3),(3,1); +CREATE TABLE t2(a INT); +INSERT INTO t2 VALUES (1); +SET @var=NULL; +SELECT @var:=(SELECT f2 FROM t2 WHERE @var) FROM t1 GROUP BY f1 ORDER BY f2 DESC +LIMIT 1; +@var:=(SELECT f2 FROM t2 WHERE @var) +NULL +SELECT @var; +@var +NULL +DROP TABLE t1, t2; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (0),(1),(3); +SELECT DISTINCT POW(COUNT(distinct a), @a:=(SELECT 1 FROM t1 LEFT JOIN t1 AS t2 ON @a limit 1)) AS b FROM t1 GROUP BY a; +b +1 +SELECT @a; +@a +1 +DROP TABLE t1; End of 5.5 tests diff --git a/mysql-test/suite/federated/federatedx.test b/mysql-test/suite/federated/federatedx.test index fd2f363ff90..15fdd47c4da 100644 --- a/mysql-test/suite/federated/federatedx.test +++ b/mysql-test/suite/federated/federatedx.test @@ -1999,4 +1999,4 @@ connection slave; SET @@GLOBAL.CONCURRENT_INSERT= @OLD_SLAVE_CONCURRENT_INSERT; connection default; -source suite/federated/include/federated_cleanup.inc; +source include/federated_cleanup.inc; diff --git a/mysql-test/suite/heap/heap_hash.result b/mysql-test/suite/heap/heap_hash.result index ac62427c81c..55d43588403 100644 --- a/mysql-test/suite/heap/heap_hash.result +++ b/mysql-test/suite/heap/heap_hash.result @@ -382,6 +382,26 @@ INSERT INTO t1 VALUES('A ', 'A '); ERROR 23000: Duplicate entry 'A -A ' for key 'key1' DROP TABLE t1; End of 5.0 tests +# +# MDEV-568 (AKA LP BUG#1007981, AKA MySQL bug#44771) +# Wrong result for a hash index look-up if the index is unique and +# the key is NULL +# +CREATE TABLE t1 ( pk INT PRIMARY KEY, val INT, UNIQUE KEY USING HASH(val)) ENGINE=MEMORY; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (2, NULL); +INSERT INTO t1 VALUES (3, 1); +INSERT INTO t1 VALUES (4, NULL); +EXPLAIN SELECT * FROM t1 WHERE val IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref val val 5 const 1 Using where +SELECT * FROM t1 WHERE val IS NULL; +pk val +4 NULL +2 NULL +1 NULL +drop table t1; +End of 5.2 tests # bit index in heap tables create table t1 (a bit(63) not null) engine=heap; insert into t1 values (869751),(736494),(226312),(802616),(728912); diff --git a/mysql-test/suite/heap/heap_hash.test b/mysql-test/suite/heap/heap_hash.test index 80d6ef9c8f2..3fe95e14205 100644 --- a/mysql-test/suite/heap/heap_hash.test +++ b/mysql-test/suite/heap/heap_hash.test @@ -285,6 +285,23 @@ DROP TABLE t1; --echo End of 5.0 tests +--echo # +--echo # MDEV-568 (AKA LP BUG#1007981, AKA MySQL bug#44771) +--echo # Wrong result for a hash index look-up if the index is unique and +--echo # the key is NULL +--echo # +CREATE TABLE t1 ( pk INT PRIMARY KEY, val INT, UNIQUE KEY USING HASH(val)) ENGINE=MEMORY; + +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (2, NULL); +INSERT INTO t1 VALUES (3, 1); +INSERT INTO t1 VALUES (4, NULL); +EXPLAIN SELECT * FROM t1 WHERE val IS NULL; +SELECT * FROM t1 WHERE val IS NULL; +drop table t1; + +--echo End of 5.2 tests + -- echo # bit index in heap tables create table t1 (a bit(63) not null) engine=heap; diff --git a/mysql-test/suite/innodb/t/innodb_information_schema_buffer.test b/mysql-test/suite/innodb/t/innodb_information_schema_buffer.test index b9c6aecd177..751a2bd6b5e 100644 --- a/mysql-test/suite/innodb/t/innodb_information_schema_buffer.test +++ b/mysql-test/suite/innodb/t/innodb_information_schema_buffer.test @@ -3,11 +3,6 @@ -- source include/have_innodb.inc -if (`select plugin_auth_version <= "1.1.8-29.0" from information_schema.plugins where plugin_name='innodb'`) -{ - --skip Not fixed in XtraDB 1.1.8-29.0 or earlier -} - -- disable_result_log SELECT * FROM INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STATS; diff --git a/mysql-test/suite/plugins/r/audit_null.result b/mysql-test/suite/plugins/r/audit_null.result new file mode 100644 index 00000000000..4cf648510e6 --- /dev/null +++ b/mysql-test/suite/plugins/r/audit_null.result @@ -0,0 +1,29 @@ +set @old_global_general_log=@@global.general_log; +set global general_log=OFF; +install plugin audit_null soname 'adt_null'; +select 1; +1 +1 +select foobar; +ERROR 42S22: Unknown column 'foobar' in 'field list' +show status like 'audit_null%'; +Variable_name Value +Audit_null_called 9 +Audit_null_general_error 1 +Audit_null_general_log 3 +Audit_null_general_result 2 +create procedure au1(x char(16)) select concat("test1", x); +call au1("-12"); +concat("test1", x) +test1-12 +show status like 'audit_null%'; +Variable_name Value +Audit_null_called 19 +Audit_null_general_error 1 +Audit_null_general_log 7 +Audit_null_general_result 5 +uninstall plugin audit_null; +Warnings: +Warning 1620 Plugin is busy and will be uninstalled on shutdown +drop procedure au1; +set global general_log=@old_global_general_log; diff --git a/mysql-test/suite/plugins/t/audit_null.test b/mysql-test/suite/plugins/t/audit_null.test new file mode 100644 index 00000000000..428fd0c276e --- /dev/null +++ b/mysql-test/suite/plugins/t/audit_null.test @@ -0,0 +1,30 @@ + +--source include/not_embedded.inc + +if (!$ADT_NULL_SO) { + skip No NULL_AUDIT plugin; +} + +set @old_global_general_log=@@global.general_log; +set global general_log=OFF; + +--disable_ps_protocol +install plugin audit_null soname 'adt_null'; + +select 1; +--error 1054 +select foobar; + +show status like 'audit_null%'; + +create procedure au1(x char(16)) select concat("test1", x); +call au1("-12"); + +show status like 'audit_null%'; + +uninstall plugin audit_null; +--enable_ps_protocol + +drop procedure au1; +set global general_log=@old_global_general_log; + diff --git a/mysql-test/suite/sys_vars/r/innodb_buffer_pool_populate_basic.result b/mysql-test/suite/sys_vars/r/innodb_buffer_pool_populate_basic.result new file mode 100644 index 00000000000..d9d067c2cf9 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_buffer_pool_populate_basic.result @@ -0,0 +1 @@ +XtraDB extension diff --git a/mysql-test/suite/sys_vars/t/innodb_buffer_pool_populate_basic.test b/mysql-test/suite/sys_vars/t/innodb_buffer_pool_populate_basic.test new file mode 100644 index 00000000000..00aa476e8d2 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_buffer_pool_populate_basic.test @@ -0,0 +1 @@ +--echo XtraDB extension diff --git a/mysql-test/suite/vcol/inc/vcol_trigger_sp.inc b/mysql-test/suite/vcol/inc/vcol_trigger_sp.inc index ddf13fef6a1..eb7e6ad32b9 100644 --- a/mysql-test/suite/vcol/inc/vcol_trigger_sp.inc +++ b/mysql-test/suite/vcol/inc/vcol_trigger_sp.inc @@ -108,3 +108,44 @@ select * from t1; drop table t1,t2; drop procedure p1; + +--echo # +--echo # Bug mdev-3845: values of virtual columns are not computed for triggers +--echo # + +CREATE TABLE t1 ( + a INTEGER UNSIGNED NULL DEFAULT NULL, + b INTEGER UNSIGNED GENERATED ALWAYS AS (a) VIRTUAL +); + +CREATE TABLE t2 (c INTEGER UNSIGNED NOT NULL); + +DELIMITER |; + +CREATE TRIGGER t1_ins_aft + AFTER INSERT + ON t1 + FOR EACH ROW +BEGIN + INSERT INTO t2 (c) VALUES (NEW.b); +END | + +CREATE TRIGGER t1_del_bef + BEFORE DELETE + ON t1 + FOR EACH ROW +BEGIN + INSERT INTO t2 (c) VALUES (OLD.b); +END | + +DELIMITER ;| + +INSERT INTO t1 (a) VALUES (1), (2), (3); +SELECT * FROM t2; +DELETE FROM t1; +SELECT * FROM t2; + +DROP TRIGGER t1_ins_aft; +DROP TRIGGER t1_del_bef; +DROP TABLE t1,t2; + diff --git a/mysql-test/suite/vcol/r/vcol_trigger_sp_innodb.result b/mysql-test/suite/vcol/r/vcol_trigger_sp_innodb.result index e903bc4eafd..1d78bbf50e4 100644 --- a/mysql-test/suite/vcol/r/vcol_trigger_sp_innodb.result +++ b/mysql-test/suite/vcol/r/vcol_trigger_sp_innodb.result @@ -85,3 +85,43 @@ a b c 300 30 30 drop table t1,t2; drop procedure p1; +# +# Bug mdev-3845: values of virtual columns are not computed for triggers +# +CREATE TABLE t1 ( +a INTEGER UNSIGNED NULL DEFAULT NULL, +b INTEGER UNSIGNED GENERATED ALWAYS AS (a) VIRTUAL +); +CREATE TABLE t2 (c INTEGER UNSIGNED NOT NULL); +CREATE TRIGGER t1_ins_aft +AFTER INSERT +ON t1 +FOR EACH ROW +BEGIN +INSERT INTO t2 (c) VALUES (NEW.b); +END | +CREATE TRIGGER t1_del_bef +BEFORE DELETE +ON t1 +FOR EACH ROW +BEGIN +INSERT INTO t2 (c) VALUES (OLD.b); +END | +INSERT INTO t1 (a) VALUES (1), (2), (3); +SELECT * FROM t2; +c +1 +2 +3 +DELETE FROM t1; +SELECT * FROM t2; +c +1 +2 +3 +1 +2 +3 +DROP TRIGGER t1_ins_aft; +DROP TRIGGER t1_del_bef; +DROP TABLE t1,t2; diff --git a/mysql-test/suite/vcol/r/vcol_trigger_sp_myisam.result b/mysql-test/suite/vcol/r/vcol_trigger_sp_myisam.result index c2a66d656b5..77efa8fe6b9 100644 --- a/mysql-test/suite/vcol/r/vcol_trigger_sp_myisam.result +++ b/mysql-test/suite/vcol/r/vcol_trigger_sp_myisam.result @@ -85,3 +85,43 @@ a b c 300 30 30 drop table t1,t2; drop procedure p1; +# +# Bug mdev-3845: values of virtual columns are not computed for triggers +# +CREATE TABLE t1 ( +a INTEGER UNSIGNED NULL DEFAULT NULL, +b INTEGER UNSIGNED GENERATED ALWAYS AS (a) VIRTUAL +); +CREATE TABLE t2 (c INTEGER UNSIGNED NOT NULL); +CREATE TRIGGER t1_ins_aft +AFTER INSERT +ON t1 +FOR EACH ROW +BEGIN +INSERT INTO t2 (c) VALUES (NEW.b); +END | +CREATE TRIGGER t1_del_bef +BEFORE DELETE +ON t1 +FOR EACH ROW +BEGIN +INSERT INTO t2 (c) VALUES (OLD.b); +END | +INSERT INTO t1 (a) VALUES (1), (2), (3); +SELECT * FROM t2; +c +1 +2 +3 +DELETE FROM t1; +SELECT * FROM t2; +c +1 +2 +3 +1 +2 +3 +DROP TRIGGER t1_ins_aft; +DROP TRIGGER t1_del_bef; +DROP TABLE t1,t2; diff --git a/mysql-test/t/derived_opt.test b/mysql-test/t/derived_opt.test index c2f831036e1..b01c479111b 100644 --- a/mysql-test/t/derived_opt.test +++ b/mysql-test/t/derived_opt.test @@ -212,5 +212,65 @@ INSERT INTO t1 VALUES ( (SELECT 1 FROM ( SELECT * FROM t1 ) as a) ); drop table t1; set optimizer_switch=@save_optimizer_switch; +--echo # +--echo # MDEV-3801 Reproducible sub select join crash on 5.3.8 and 5.3.9 +--echo # + +CREATE TABLE t1 ( + pk int(10) unsigned NOT NULL AUTO_INCREMENT, + a char(2) DEFAULT NULL, + PRIMARY KEY (pk), + KEY a (a) +) ENGINE=MyISAM; +INSERT INTO t1 (a) +VALUES (NULL),(NULL),(NULL),('AB'),(NULL),('CD'),(NULL),(NULL); +INSERT INTO t1 SELECT NULL, a1.a FROM t1 a1, t1 a2, t1 a3, t1 a4, t1 a5; + +CREATE TABLE t2 ( + pk int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t2 SELECT NULL FROM t2 a1, t2 a2, t2 a3, t2 a4, t2 a5; + +CREATE TABLE t3 ( + pk int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY +) ENGINE=MyISAM; +INSERT INTO t3 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t3 SELECT NULL FROM t3 a1, t3 a2, t3 a3, t3 a4, t3 a5; + +CREATE TABLE t4 ( + a char(2) NOT NULL DEFAULT '', + PRIMARY KEY (a) +) ENGINE=MyISAM; +INSERT INTO t4 VALUES ('CD'); + +set @@tmp_table_size=8192; + +--replace_column 9 # +EXPLAIN +SELECT * FROM t3 AS tx JOIN t2 AS ty ON (tx.pk = ty.pk) +WHERE + tx.pk IN + (SELECT * + FROM (SELECT DISTINCT ta.pk + FROM t3 AS ta + JOIN t2 AS tb ON (ta.pk = tb.pk) + JOIN t1 AS tc ON (tb.pk = tc.pk) + JOIN t4 AS td ON tc.a = td.a) tu) +limit 10; + +SELECT * FROM t3 AS tX JOIN t2 AS tY ON (tX.pk = tY.pk) +WHERE + tX.pk IN + (SELECT * + FROM (SELECT DISTINCT tA.pk + FROM t3 AS tA + JOIN t2 AS tB ON (tA.pk = tB.pk) + JOIN t1 AS tC ON (tB.pk = tC.pk) + JOIN t4 AS tD ON tC.a = tD.a) tU) +limit 10; + +drop table t1, t2, t3, t4; + # The following command must be the last one the file set optimizer_switch=@exit_optimizer_switch; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 1226683ba03..3af531418c5 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -1469,6 +1469,20 @@ WHERE a = ( GROUP BY 1; DROP TABLE t1, t2; +# +# MDEV-736 LP:1004615 - Unexpected warnings "Encountered illegal value '' when converting to DECIMAL" on a query with aggregate functions and GROUP BY +# + +FLUSH STATUS; # this test case *must* use Aria temp tables + +CREATE TABLE t1 (f1 INT, f2 decimal(20,1), f3 blob); +INSERT INTO t1 values(11,NULL,'blob'),(11,NULL,'blob'); +SELECT f3, MIN(f2) FROM t1 GROUP BY f1 LIMIT 1; +DROP TABLE t1; + +--echo the value below *must* be 1 +show status like 'Created_tmp_disk_tables'; + --echo # End of 5.3 tests --echo # diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index b0f8ddd375f..e95f41f6c8d 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -1444,6 +1444,17 @@ SELECT length(CAST(b AS CHAR)) FROM ubig; DROP TABLE ubig; +# +# Bug #13889741: HANDLE_FATAL_SIGNAL IN _DB_ENTER_ | HANDLE_FATAL_SIGNAL IN STRNLEN +# +select 1 from information_schema.tables where table_schema=repeat('a', 2000); +grant usage on *.* to mysqltest_1@localhost; +connect (con1, localhost, mysqltest_1,,); +connection con1; +select 1 from information_schema.tables where table_schema=repeat('a', 2000); +connection default; +disconnect con1; +drop user mysqltest_1@localhost; --echo End of 5.1 tests. diff --git a/mysql-test/t/information_schema_all_engines.test b/mysql-test/t/information_schema_all_engines.test index a5400e8287a..553367d2b9a 100644 --- a/mysql-test/t/information_schema_all_engines.test +++ b/mysql-test/t/information_schema_all_engines.test @@ -15,6 +15,7 @@ show tables; # Bug#18925: subqueries with MIN/MAX functions on INFORMATION_SCHEMA # +--sorted_result SELECT t.table_name, c1.column_name FROM information_schema.tables t INNER JOIN @@ -29,6 +30,7 @@ SELECT t.table_name, c1.column_name c2.table_name = t.table_name AND c2.column_name LIKE '%SCHEMA%' ) order by t.table_name; +--sorted_result SELECT t.table_name, c1.column_name FROM information_schema.tables t INNER JOIN diff --git a/mysql-test/t/innodb_ext_key.test b/mysql-test/t/innodb_ext_key.test index 58d692f720d..3e82403ddb5 100644 --- a/mysql-test/t/innodb_ext_key.test +++ b/mysql-test/t/innodb_ext_key.test @@ -287,6 +287,27 @@ select o_orderkey, p_partkey and o_orderkey=l_orderkey and p_partkey=l_partkey; show status like 'handler_read%'; +--echo # +--echo # Bug mdev-3851: ref access used instead of expected eq_ref access +--echo # when extended_keys=on +--echo # + +create table t0 (a int); +insert into t0 values (1), (2), (3), (4), (5); +create index i_p_size on part(p_size); + +set optimizer_switch='extended_keys=on'; + +explain +select * from t0, part ignore index (primary) + where p_partkey=t0.a and p_size=1; + +select * from t0, part ignore index (primary) + where p_partkey=t0.a and p_size=1; + +drop table t0; +drop index i_p_size on part; + DROP DATABASE dbt3_s001; use test; @@ -407,5 +428,44 @@ set optimizer_switch=@save_optimizer_switch; DROP TABLE t1,t2; + +--echo # +--echo # Bug mdev-3888: INSERT with UPDATE on duplicate keys +--echo # with extended_keys=on +--echo # + +CREATE TABLE t1 ( +c1 bigint(20) unsigned NOT NULL AUTO_INCREMENT, +c2 bigint(20) unsigned NOT NULL, +c3 bigint(20) unsigned NOT NULL, +c4 varchar(128) DEFAULT NULL, +PRIMARY KEY (c1), +UNIQUE KEY uq (c2,c3), +KEY c3 (c3), +KEY c4 (c4) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; + + +set @save_optimizer_switch=@@optimizer_switch; + +set session optimizer_switch='extended_keys=off'; +INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') + ON DUPLICATE KEY UPDATE c4 = VALUES(c4); +INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') + ON DUPLICATE KEY UPDATE c4 = VALUES(c4); + +DELETE FROM t1; + +set session optimizer_switch='extended_keys=on'; +INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') + ON DUPLICATE KEY UPDATE c4 = VALUES(c4); +INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') + ON DUPLICATE KEY UPDATE c4 = VALUES(c4); + +set optimizer_switch=@save_optimizer_switch; + +DROP TABLE t1; + set optimizer_switch=@save_ext_key_optimizer_switch; SET SESSION STORAGE_ENGINE=DEFAULT; + diff --git a/mysql-test/t/mysqlshow.test b/mysql-test/t/mysqlshow.test index 2b6b5b631b2..5dba7fa5b85 100644 --- a/mysql-test/t/mysqlshow.test +++ b/mysql-test/t/mysqlshow.test @@ -29,7 +29,7 @@ select "---- -v -v -t ------" as ""; DROP TABLE t1, t2; -if (`select count(*) from information_schema.plugins where plugin_name='innodb' and plugin_auth_version > "1.1.8-29.0"`) +if (`select count(*) from information_schema.plugins where plugin_name='innodb' and plugin_auth_version > "1.1.8-29.1"`) { # because of lp:1066512 this test shows xtradb I_S plugins, even when # xtradb is supposed to be disabled diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 2912e190af8..3e20d22d726 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -1652,3 +1652,68 @@ DROP TABLE t1; --echo End of 5.3 tests +--echo # +--echo # Bug 54599: discarded fast range scan for query with +--echo # GROUP BY + ORDER BY + LIMIT +--echo # + +create table t0 (a int); +insert into t0 values (0), (1), (2), (3), (4), (5), (6), (7), (8), (9); + +create table t1 (a int, b int, index idx1(a,b), index idx2(b,a)); +insert into t1 + select 1000*s4.a+100*s3.a+10*s2.a + s1.a, 1000*s4.a+100*s3.a+10*s2.a+s1.a + from t0 s1, t0 s2, t0 s3, t0 s4; +--disable_result_log +analyze table t1; +--enable_result_log + +explain +select b, count(*) num_cnt from t1 + where a > 9750 group by b order by num_cnt; +flush status; +--disable_result_log +select b, count(*) num_cnt from t1 + where a > 9750 group by b order by num_cnt; +--enable_result_log +show status like '%Handler_read%'; + +explain +select b, count(*) num_cnt from t1 + where a > 9750 group by b order by num_cnt limit 1; +flush status; +--disable_result_log +select b, count(*) num_cnt from t1 + where a > 9750 group by b order by num_cnt limit 1; +--enable_result_log +show status like '%Handler_read%'; + +drop table t0, t1; + +--echo # +--echo # LP bug #1002508 : the number of expected rows to be examined is off +--echo # (bug #13528826) +--echo # + +CREATE TABLE t1(a int PRIMARY KEY, b int) ENGINE=myisam; +INSERT INTO t1 VALUES + (5, 10), (2, 70), (7, 80), (6, 20), (1, 50), (9, 40), (8, 30), (3, 60); +CREATE TABLE t2 (p int, a int, INDEX i_a(a)) ENGINE=myisam; +INSERT INTO t2 VALUES + (103, 7), (109, 3), (102, 3), (108, 1), (106, 3), + (107, 7), (105, 1), (101, 3), (100, 7), (110, 1); + +EXPLAIN +SELECT t1.a FROM t1 LEFT JOIN t2 ON t1.a=t2.a ORDER BY t1.a; + +EXPLAIN +SELECT t1.a FROM t1 LEFT JOIN t2 ON t1.a=t2.a ORDER BY t1.a LIMIT 8; + +EXPLAIN +SELECT t1.a FROM t1 LEFT JOIN t2 ON t1.a=t2.a ORDER BY t1.a LIMIT 100; + +DROP TABLE t1,t2; + +--echo End of 5.5 tests + + diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index ef0d3df6661..038907702d5 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -2395,6 +2395,14 @@ SELECT 1 FROM t1 WHERE b < SOME DROP TABLE t1; +--echo +--echo MDEV-612 Valgrind error in ha_maria::check_if_incompatible_data +--echo + +CREATE TABLE t1 (a INT, b INT, KEY(a)) ENGINE=Aria PARTITION BY KEY(a) PARTITIONS 2; +ALTER TABLE t1 ADD KEY (b); +drop table t1; + --echo End of 5.1 tests --echo # diff --git a/mysql-test/t/range_vs_index_merge.test b/mysql-test/t/range_vs_index_merge.test index 613a7cf5760..fb8fd778559 100755 --- a/mysql-test/t/range_vs_index_merge.test +++ b/mysql-test/t/range_vs_index_merge.test @@ -675,6 +675,64 @@ SELECT Name, Country, Population FROM City WHERE $cond; set optimizer_switch=@save_optimizer_switch; + +--echo # +--echo # Bug mdev-585: range vs index-merge with ORDER BY ... LIMIT n +--echo # (LP bug #637962) +--echo # + +DROP INDEX CountryPopulation ON City; +DROP INDEX CountryName ON City; +DROP INDEX CityName on City; + +CREATE INDEX Name ON City(Name); +CREATE INDEX Population ON City(Population); + + +--replace_column 9 # +EXPLAIN +SELECT * FROM City + WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) + AND (Population >= 100000 AND Population < 120000); +FLUSH STATUS; +SELECT * FROM City + WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) + AND (Population >= 100000 AND Population < 120000); +SHOW STATUS LIKE 'Handler_read_%'; + + +--replace_column 9 # +EXPLAIN +SELECT * FROM City + WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) + AND (Population >= 100000 AND Population < 120000) +ORDER BY Population LIMIT 5; + +FLUSH STATUS; +SELECT * FROM City + WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) + AND (Population >= 100000 AND Population < 120000) +ORDER BY Population LIMIT 5; +SHOW STATUS LIKE 'Handler_read_%'; + + +set optimizer_switch='index_merge=off'; + +--replace_column 9 # +EXPLAIN +SELECT * FROM City + WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) + AND (Population >= 100000 AND Population < 120000) +ORDER BY Population LIMIT 5; + +FLUSH STATUS; +SELECT * FROM City + WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H')) + AND (Population >= 100000 AND Population < 120000) +ORDER BY Population LIMIT 5; +SHOW STATUS LIKE 'Handler_read_%'; + +set optimizer_switch=@save_optimizer_switch; DROP DATABASE world; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 07f0084e7ab..e7cb505b19f 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -5078,6 +5078,82 @@ SELECT col_int_nokey FROM ot DROP TABLE ot,it1,it2; +--echo # +--echo # MDEV-746 +--echo # Bug#13651009 WRONG RESULT FROM DERIVED TABLE IF THE SUBQUERY +--echo # HAS AN EMPTY RESULT +--echo # + +CREATE TABLE t1 ( + pk int NOT NULL, + col_int_nokey int NOT NULL, + col_int_key int NOT NULL, + col_time_key time NOT NULL, + col_varchar_key varchar(1) NOT NULL, + col_varchar_nokey varchar(1) NOT NULL, + PRIMARY KEY (pk), + KEY col_int_key (col_int_key), + KEY col_time_key (col_time_key), + KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; + +CREATE TABLE t2 ( + pk int NOT NULL AUTO_INCREMENT, + col_int_nokey int NOT NULL, + col_int_key int NOT NULL, + col_time_key time NOT NULL, + col_varchar_key varchar(1) NOT NULL, + col_varchar_nokey varchar(1) NOT NULL, + PRIMARY KEY (pk), + KEY col_int_key (col_int_key), + KEY col_time_key (col_time_key), + KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; + +INSERT INTO t2 VALUES (1,4,4,'00:00:00','b','b'); + +SET @var2:=4, @var3:=8; + +--echo +--echo Testcase without inner subquery + +let $subq= +SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR + sq4_alias1.col_varchar_key = @var3; + +eval EXPLAIN $subq; +eval $subq; +SELECT @var3; + +# Now as derived table: +eval EXPLAIN SELECT * FROM ( $subq ) AS alias3; +eval SELECT * FROM ( $subq ) AS alias3; +SELECT @var3; + +--echo +--echo Testcase with inner subquery; crashed WL#6095 +SET @var3=8; +let $subq= +SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) + NOT IN + (SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, + c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 + FROM t2 AS c_sq1_alias1 + WHERE (c_sq1_alias1.col_int_nokey != @var2 + OR c_sq1_alias1.pk != @var3)); + +eval EXPLAIN $subq; +eval $subq; +# Now as derived table: +eval EXPLAIN SELECT * FROM ( $subq ) AS alias3; +eval SELECT * FROM ( $subq ) AS alias3; + +DROP TABLE t1,t2; + --echo End of 5.2 tests --echo # diff --git a/mysql-test/t/subselect2.test b/mysql-test/t/subselect2.test index 75cf842fbdb..68894ad18cb 100644 --- a/mysql-test/t/subselect2.test +++ b/mysql-test/t/subselect2.test @@ -203,6 +203,32 @@ SET optimizer_switch=@tmp_optimizer_switch; DROP VIEW v1; DROP TABLE t1,t2,t3; +--echo # +--echo # MDEV-536: LP:1050806 - different result for a query using subquery +--echo # +DROP TABLE IF EXISTS `t1`; + +CREATE TABLE `t1` ( + `node_uid` bigint(20) unsigned DEFAULT NULL, + `date` datetime DEFAULT NULL, + `mirror_date` datetime DEFAULT NULL, + KEY `date` (`date`) +) ENGINE=MyISAM; + +INSERT INTO `t1` VALUES (2085,'2012-01-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2084,'2012-02-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2088,'2012-03-01 00:00:00','2013-01-01 00:00:00'); + +SELECT * FROM ( + SELECT node_uid, date, mirror_date, @result := 0 AS result + FROM t1 + WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) + ORDER BY mirror_date ASC +) AS calculated_result; + +DROP TABLE t1; + --echo # --echo # MDEV-567: Wrong result from a query with correlated subquery if ICP is allowed --echo # @@ -220,7 +246,75 @@ SELECT * FROM t3 WHERE t1.a = t2.a AND t2.a BETWEEN 7 AND 9 AND t3.b = t1.b GROUP BY t1.b); -DROP TABLE t1, t2, t3; + + +set @tmp_mdev567=@@optimizer_switch; +set optimizer_switch='mrr=off'; +SELECT * FROM t3 + WHERE a = (SELECT COUNT(DISTINCT t2.b) FROM t1, t2 + WHERE t1.a = t2.a AND t2.a BETWEEN 7 AND 9 + AND t3.b = t1.b + GROUP BY t1.b); + +DROP TABLE t1,t2,t3; +set optimizer_switch=@tmp_mdev567; + +--echo # +--echo # MDEV-614, also MDEV-536, also LP:1050806: +--echo # different result for a query using subquery between 5.5.25 and 5.5.27 +--echo # + +CREATE TABLE `t1` ( + `node_uid` bigint(20) unsigned DEFAULT NULL, + `date` datetime DEFAULT NULL, + `mirror_date` datetime DEFAULT NULL, + KEY `date` (`date`) +) ENGINE=MyISAM; + +INSERT INTO `t1` VALUES (2085,'2012-01-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2084,'2012-02-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2088,'2012-03-01 00:00:00','2013-01-01 00:00:00'); + +explain +SELECT * FROM ( + SELECT node_uid, date, mirror_date, @result := 0 AS result + FROM t1 + WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) + ORDER BY mirror_date ASC +) AS calculated_result; + +SELECT * FROM ( + SELECT node_uid, date, mirror_date, @result := 0 AS result + FROM t1 + WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) + ORDER BY mirror_date ASC +) AS calculated_result; + +set @tmp_mdev614=@@optimizer_switch; +set optimizer_switch='mrr=off'; +explain +SELECT * FROM ( + SELECT node_uid, date, mirror_date, @result := 0 AS result + FROM t1 + WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) + ORDER BY mirror_date ASC +) AS calculated_result; + +SELECT * FROM ( + SELECT node_uid, date, mirror_date, @result := 0 AS result + FROM t1 + WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) + ORDER BY mirror_date ASC +) AS calculated_result; + +set optimizer_switch=@tmp_mdev614; + +DROP TABLE t1; + set optimizer_switch=@subselect2_test_tmp; diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index f509a1ad0f2..c6c4e4d9d2f 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -424,4 +424,32 @@ DROP TABLE t1; SET @bug12408412=1; SELECT GROUP_CONCAT(@bug12408412 ORDER BY 1) INTO @bug12408412; +# +# MDEV-616 LP BUG#1002126 +# Bug #11764371 57196: MORE FUN WITH ASSERTION: !TABLE->FILE || +# TABLE->FILE->INITED == HANDLER:: +# + +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (0); +SELECT DISTINCT POW(COUNT(*), @a:=(SELECT 1 FROM t1 LEFT JOIN t1 AS t2 ON @a)) +AS b FROM t1 GROUP BY a; +SELECT @a; +DROP TABLE t1; +CREATE TABLE t1(f1 INT, f2 INT); +INSERT INTO t1 VALUES (1,2),(2,3),(3,1); +CREATE TABLE t2(a INT); +INSERT INTO t2 VALUES (1); +SET @var=NULL; +SELECT @var:=(SELECT f2 FROM t2 WHERE @var) FROM t1 GROUP BY f1 ORDER BY f2 DESC +LIMIT 1; +SELECT @var; +DROP TABLE t1, t2; + +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (0),(1),(3); +SELECT DISTINCT POW(COUNT(distinct a), @a:=(SELECT 1 FROM t1 LEFT JOIN t1 AS t2 ON @a limit 1)) AS b FROM t1 GROUP BY a; +SELECT @a; +DROP TABLE t1; + --echo End of 5.5 tests diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c index 18c9a38f0db..a51d94f8e73 100644 --- a/mysys/mf_pack.c +++ b/mysys/mf_pack.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. + Copyright (c) 2012, Monty Program Ab 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 @@ -30,7 +31,7 @@ void pack_dirname(char * to, const char *from) int cwd_err; size_t d_length,length,UNINIT_VAR(buff_length); char * start; - char buff[FN_REFLEN]; + char buff[FN_REFLEN + 1]; DBUG_ENTER("pack_dirname"); (void) intern_filename(to,from); /* Change to intern name */ @@ -127,7 +128,7 @@ size_t cleanup_dirname(register char *to, const char *from) reg3 char * from_ptr; reg4 char * start; char parent[5], /* for "FN_PARENTDIR" */ - buff[FN_REFLEN+1],*end_parentdir; + buff[FN_REFLEN + 1],*end_parentdir; #ifdef BACKSLASH_MBTAIL CHARSET_INFO *fs= fs_character_set(); #endif @@ -241,7 +242,7 @@ my_bool my_use_symdir=0; /* Set this if you want to use symdirs */ #ifdef USE_SYMDIR void symdirget(char *dir) { - char buff[FN_REFLEN+1]; + char buff[FN_REFLEN + 1]; char *pos=strend(dir); if (dir[0] && pos[-1] != FN_DEVCHAR && my_access(dir, F_OK)) { @@ -291,7 +292,7 @@ void symdirget(char *dir) size_t normalize_dirname(char *to, const char *from) { size_t length; - char buff[FN_REFLEN]; + char buff[FN_REFLEN + 1]; DBUG_ENTER("normalize_dirname"); /* @@ -418,7 +419,7 @@ static char * expand_tilde(char **path) size_t unpack_filename(char * to, const char *from) { size_t length, n_length, buff_length; - char buff[FN_REFLEN]; + char buff[FN_REFLEN + 1]; DBUG_ENTER("unpack_filename"); length=dirname_part(buff, from, &buff_length);/* copy & convert dirname */ @@ -448,7 +449,7 @@ size_t system_filename(char *to, const char *from) char *intern_filename(char *to, const char *from) { size_t length, to_length; - char buff[FN_REFLEN]; + char buff[FN_REFLEN + 1]; if (from == to) { /* Dirname may destroy from */ strmov(buff,from); diff --git a/mysys/my_context.c b/mysys/my_context.c index 9d56b13ecb5..08dc0920f21 100644 --- a/mysys/my_context.c +++ b/mysys/my_context.c @@ -206,7 +206,7 @@ my_context_spawn(struct my_context *c, void (*f)(void *), void *d) ( "movq %%rsp, (%[save])\n\t" "movq %[stack], %%rsp\n\t" -#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 && !defined(__INTEL_COMPILER) /* This emits a DWARF DW_CFA_undefined directive to make the return address undefined. This indicates that this is the top of the stack frame, and @@ -456,7 +456,7 @@ my_context_spawn(struct my_context *c, void (*f)(void *), void *d) ( "movl %%esp, (%[save])\n\t" "movl %[stack], %%esp\n\t" -#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 && !defined(__INTEL_COMPILER) /* This emits a DWARF DW_CFA_undefined directive to make the return address undefined. This indicates that this is the top of the stack frame, and diff --git a/plugin/audit_null/audit_null.c b/plugin/audit_null/audit_null.c index 469e5ae494c..be0c70fbd35 100644 --- a/plugin/audit_null/audit_null.c +++ b/plugin/audit_null/audit_null.c @@ -145,7 +145,7 @@ mysql_declare_plugin(audit_null) { MYSQL_AUDIT_PLUGIN, /* type */ &audit_null_descriptor, /* descriptor */ - "NULL_AUDIT", /* name */ + "AUDIT_NULL", /* name */ "Oracle Corp", /* author */ "Simple NULL Audit", /* description */ PLUGIN_LICENSE_GPL, diff --git a/plugin/feedback/CMakeLists.txt b/plugin/feedback/CMakeLists.txt index 627e4d643fb..3e14ef3918b 100644 --- a/plugin/feedback/CMakeLists.txt +++ b/plugin/feedback/CMakeLists.txt @@ -1,9 +1,11 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql ${CMAKE_SOURCE_DIR}/regex - ${CMAKE_SOURCE_DIR}/extra/yassl/include) + ${SSL_INCLUDE_DIRS}) SET(FEEDBACK_SOURCES feedback.cc sender_thread.cc url_base.cc url_http.cc utils.cc) +ADD_DEFINITIONS(${SSL_DEFINES}) + INCLUDE (CheckIncludeFiles) CHECK_INCLUDE_FILES (netdb.h HAVE_NETDB_H) IF(HAVE_NETDB_H) @@ -11,8 +13,10 @@ IF(HAVE_NETDB_H) ENDIF(HAVE_NETDB_H) IF(WIN32) - #SET(FEEDBACK_LIBS Ws2_32) - MYSQL_ADD_PLUGIN(FEEDBACK ${FEEDBACK_SOURCES} STATIC_ONLY DEFAULT) + MYSQL_ADD_PLUGIN(FEEDBACK ${FEEDBACK_SOURCES} + LINK_LIBRARIES ${SSL_LIBRARIES} + STATIC_ONLY DEFAULT) ELSE(WIN32) - MYSQL_ADD_PLUGIN(FEEDBACK ${FEEDBACK_SOURCES}) + MYSQL_ADD_PLUGIN(FEEDBACK ${FEEDBACK_SOURCES} + LINK_LIBRARIES ${SSL_LIBRARIES}) ENDIF(WIN32) diff --git a/plugin/feedback/url_http.cc b/plugin/feedback/url_http.cc index a9d4c5bbbaf..dd39adbf7a7 100644 --- a/plugin/feedback/url_http.cc +++ b/plugin/feedback/url_http.cc @@ -29,12 +29,6 @@ namespace feedback { static const uint FOR_READING= 0; static const uint FOR_WRITING= 1; -#ifdef MARIADB_BASE_VERSION -#define ssl_connect(A,B,C,D) sslconnect(A,B,C,D) -#else -#define ssl_connect(A,B,C,D) sslconnect(A,B,C) -#endif - /** implementation of the Url class that sends the data via HTTP POST request. @@ -199,12 +193,23 @@ int Url_http::send(const char* data, size_t data_length) struct st_VioSSLFd *UNINIT_VAR(ssl_fd); if (ssl) { - buf[0]= 0; - if (!(ssl_fd= new_VioSSLConnectorFd(0, 0, 0, 0, 0)) || - ssl_connect(ssl_fd, vio, send_timeout, buf)) + enum enum_ssl_init_error ssl_init_error= SSL_INITERR_NOERROR; + ulong ssl_error= 0; + if (!(ssl_fd= new_VioSSLConnectorFd(0, 0, 0, 0, 0, &ssl_init_error)) || + sslconnect(ssl_fd, vio, send_timeout, &ssl_error)) { + const char *err; + if (ssl_init_error != SSL_INITERR_NOERROR) + err= sslGetErrString(ssl_init_error); + else + { + ERR_error_string_n(ssl_error, buf, sizeof(buf)); + buf[sizeof(buf)-1]= 0; + err= buf; + } + sql_print_error("feedback plugin: ssl failed for url '%s' %s", - full_url.str, buf); + full_url.str, err); if (ssl_fd) free_vio_ssl_acceptor_fd(ssl_fd); closesocket(fd); @@ -256,18 +261,21 @@ int Url_http::send(const char* data, size_t data_length) Extract the first string between

...

tags and put it as a server reply into the error log. */ + len= 0; for (;;) { - size_t i= vio_read(vio, (uchar*)buf + len, sizeof(buf) - len - 1); + size_t i= sizeof(buf) - len - 1; + if (i) + i= vio_read(vio, (uchar*)buf + len, i); if ((int)i <= 0) break; len+= i; } - if (len && len < sizeof(buf)) + if (len) { char *from; - buf[len+1]= 0; // safety + buf[len]= 0; // safety if ((from= strstr(buf, "

"))) { @@ -296,7 +304,7 @@ int Url_http::send(const char* data, size_t data_length) if (ssl) { SSL_CTX_free(ssl_fd->ssl_context); - my_free(ssl_fd, MYF(0)); + my_free(ssl_fd); } #endif diff --git a/scripts/mysql_config.sh b/scripts/mysql_config.sh index fd15d7ac746..38cd2b6b910 100644 --- a/scripts/mysql_config.sh +++ b/scripts/mysql_config.sh @@ -92,11 +92,7 @@ plugindir_rel=`echo $plugindir | sed -e "s;^$basedir/;;"` fix_path plugindir $plugindir_rel lib/mysql/plugin lib/plugin pkgincludedir='@pkgincludedir@' -if [ -f "$basedir/include/mysql/mysql.h" ]; then - pkgincludedir="$basedir/include/mysql" -elif [ -f "$basedir/include/mysql.h" ]; then - pkgincludedir="$basedir/include" -fi +fix_path pkgincludedir include/mysql version='@VERSION@' socket='@MYSQL_UNIX_ADDR@' @@ -125,8 +121,11 @@ if [ -r "$pkglibdir/libmygcc.a" ]; then embedded_libs="$embedded_libs -lmygcc " fi -cflags="-I$pkgincludedir @CFLAGS@ " #note: end space! include="-I$pkgincludedir" +if [ "$basedir" != "/usr" ]; then + include="$include -I$pkgincludedir/.." +fi +cflags="$include @CFLAGS@ " #note: end space! # Remove some options that a client doesn't have to care about # FIXME until we have a --cxxflags, we need to remove -Xa diff --git a/scripts/mysql_secure_installation.pl.in b/scripts/mysql_secure_installation.pl.in index de549add904..188a6bd7104 100755 --- a/scripts/mysql_secure_installation.pl.in +++ b/scripts/mysql_secure_installation.pl.in @@ -1,7 +1,7 @@ #!/usr/bin/perl # -*- cperl -*- # -# Copyright (c) 2007, 2012, Oracle and/or its affiliates +# Copyright (c) 2007, 2012, Oracle and/or its affiliates. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/scripts/mysql_secure_installation.sh b/scripts/mysql_secure_installation.sh index 28c631a46d5..9e9bce9fa87 100644 --- a/scripts/mysql_secure_installation.sh +++ b/scripts/mysql_secure_installation.sh @@ -1,6 +1,6 @@ #!/bin/sh -# Copyright (c) 2002, 2012, Oracle and/or its affiliates +# Copyright (c) 2002, 2012, Oracle and/or its affiliates. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/sql-bench/test-table-elimination.sh b/sql-bench/test-table-elimination.sh index 0dcfe975486..5b494688bec 100755 --- a/sql-bench/test-table-elimination.sh +++ b/sql-bench/test-table-elimination.sh @@ -1,4 +1,3 @@ - #!@PERL@ # Test of table elimination feature @@ -93,7 +92,7 @@ $dbh->do("create view elim_current_facts as $select_current_full_facts"); if ($opt_lock_tables) { - do_query($dbh,"LOCK TABLES elim_facts, elim_attr1, elim_attr2 WRITE"); + do_query($dbh,"LOCK TABLES elim_current_facts WRITE, elim_facts WRITE, elim_attr1 WRITE, elim_attr2 WRITE"); } if ($opt_fast && defined($server->{vacuum})) @@ -200,12 +199,14 @@ if ($opt_lock_tables) if ($opt_fast && defined($server->{vacuum})) { - $server->vacuum(0,\$dbh,["elim_facts", "elim_attr1", "elim_attr2"]); + $server->vacuum(1,\$dbh,"elim_facts"); + $server->vacuum(1,\$dbh,"elim_attr1"); + $server->vacuum(1,\$dbh,"elim_attr2"); } if ($opt_lock_tables) { - do_query($dbh,"LOCK TABLES elim_facts, elim_attr1, elim_attr2 WRITE"); + do_query($dbh,"LOCK TABLES elim_current_facts READ, elim_facts READ, elim_attr1 READ, elim_attr2 READ"); } #### diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index afd773faf32..9cbb8e16f8a 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4651,8 +4651,8 @@ int ha_partition::common_index_read(uchar *buf, bool have_start_key) bool reverse_order= FALSE; DBUG_ENTER("ha_partition::common_index_read"); - DBUG_PRINT("info", ("m_ordered %u m_ordered_scan_ong %u have_start_key %u", - m_ordered, m_ordered_scan_ongoing, have_start_key)); + DBUG_PRINT("info", ("m_ordered: %u have_start_key: %u", + m_ordered, have_start_key)); if (have_start_key) { diff --git a/sql/item_func.h b/sql/item_func.h index 586444e0e4e..f1b97151cbe 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1569,6 +1569,15 @@ public: :Item_func(b), cached_result_type(INT_RESULT), entry(NULL), entry_thread_id(0), name(a) {} + Item_func_set_user_var(Item_func_set_user_var *item) + :Item_func(item), cached_result_type(item->cached_result_type), + entry(item->entry), entry_thread_id(item->entry_thread_id), + value(item->value), decimal_buff(item->decimal_buff), + null_item(item->null_item), save_result(item->save_result), + name(item->name) + { + //fixed= 1; + } enum Functype functype() const { return SUSERVAR_FUNC; } double val_real(); longlong val_int(); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 59cb97f5983..217e65e401f 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2521,9 +2521,8 @@ Item_sum_hybrid::min_max_update_int_field() void Item_sum_hybrid::min_max_update_decimal_field() { - /* TODO: optimize: do not get result_field in case of args[0] is NULL */ my_decimal old_val, nr_val; - const my_decimal *old_nr= result_field->val_decimal(&old_val); + const my_decimal *old_nr; const my_decimal *nr= args[0]->val_decimal(&nr_val); if (!args[0]->null_value) { @@ -2531,16 +2530,17 @@ Item_sum_hybrid::min_max_update_decimal_field() old_nr=nr; else { + old_nr= result_field->val_decimal(&old_val); bool res= my_decimal_cmp(old_nr, nr) > 0; /* (cmp_sign > 0 && res) || (!(cmp_sign > 0) && !res) */ if ((cmp_sign > 0) ^ (!res)) old_nr=nr; } result_field->set_notnull(); + result_field->store_decimal(old_nr); } else if (result_field->is_null(0)) result_field->set_null(); - result_field->store_decimal(old_nr); } diff --git a/sql/log.cc b/sql/log.cc index effe0e36705..70e74de5a31 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1279,12 +1279,6 @@ bool LOGGER::general_log_write(THD *thd, enum enum_server_command command, DBUG_ASSERT(thd); - lock_shared(); - if (!opt_log) - { - unlock(); - return 0; - } user_host_len= make_user_name(thd, user_host_buff); current_time= my_hrtime(); @@ -1295,15 +1289,19 @@ bool LOGGER::general_log_write(THD *thd, enum enum_server_command command, command_name[(uint) command].length, query, query_length); - while (*current_handler) - error|= (*current_handler++)-> - log_general(thd, current_time, user_host_buff, - user_host_len, thd->thread_id, - command_name[(uint) command].str, - command_name[(uint) command].length, - query, query_length, - thd->variables.character_set_client) || error; - unlock(); + if (opt_log && log_command(thd, command)) + { + lock_shared(); + while (*current_handler) + error|= (*current_handler++)-> + log_general(thd, current_time, user_host_buff, + user_host_len, thd->thread_id, + command_name[(uint) command].str, + command_name[(uint) command].length, + query, query_length, + thd->variables.character_set_client) || error; + unlock(); + } return error; } @@ -5333,7 +5331,7 @@ bool general_log_write(THD *thd, enum enum_server_command command, const char *query, uint query_length) { /* Write the message to the log if we want to log this king of commands */ - if (logger.log_command(thd, command)) + if (logger.log_command(thd, command) || mysql_audit_general_enabled()) return logger.general_log_write(thd, command, query, query_length); return FALSE; @@ -6963,8 +6961,9 @@ int TC_LOG_MMAP::open(const char *opt_name) syncing= 0; active=pages; + DBUG_ASSERT(npages >= 2); pool=pages+1; - pool_last=pages+npages-1; + pool_last_ptr= &((pages+npages-1)->next); commit_ordered_queue= NULL; commit_ordered_queue_busy= false; @@ -6997,8 +6996,8 @@ void TC_LOG_MMAP::get_active_from_pool() do { best_p= p= &pool; - if ((*p)->waiters == 0) // can the first page be used ? - break; // yes - take it. + if ((*p)->waiters == 0 && (*p)->free > 0) // can the first page be used ? + break; // yes - take it. best_free=0; // no - trying second strategy for (p=&(*p)->next; *p; p=&(*p)->next) @@ -7015,10 +7014,10 @@ void TC_LOG_MMAP::get_active_from_pool() mysql_mutex_assert_owner(&LOCK_active); active=*best_p; - if ((*best_p)->next) // unlink the page from the pool - *best_p=(*best_p)->next; - else - pool_last=*best_p; + /* Unlink the page from the pool. */ + if (!(*best_p)->next) + pool_last_ptr= best_p; + *best_p=(*best_p)->next; mysql_mutex_unlock(&LOCK_pool); mysql_mutex_lock(&active->lock); @@ -7125,12 +7124,9 @@ int TC_LOG_MMAP::log_one_transaction(my_xid xid) mysql_mutex_unlock(&LOCK_active); mysql_mutex_lock(&p->lock); p->waiters++; - for (;;) + while (p->state == PS_DIRTY && syncing) { - int not_dirty = p->state != PS_DIRTY; mysql_mutex_unlock(&p->lock); - if (not_dirty || !syncing) - break; mysql_cond_wait(&p->cond, &LOCK_sync); mysql_mutex_lock(&p->lock); } @@ -7182,8 +7178,8 @@ int TC_LOG_MMAP::sync() /* page is synced. let's move it to the pool */ mysql_mutex_lock(&LOCK_pool); - pool_last->next=syncing; - pool_last=syncing; + (*pool_last_ptr)=syncing; + pool_last_ptr=&(syncing->next); syncing->next=0; syncing->state= err ? PS_ERROR : PS_POOL; mysql_cond_signal(&COND_pool); // in case somebody's waiting diff --git a/sql/log.h b/sql/log.h index 9b9bed1262a..e388df61b38 100644 --- a/sql/log.h +++ b/sql/log.h @@ -134,7 +134,7 @@ class TC_LOG_MMAP: public TC_LOG my_off_t file_length; uint npages, inited; uchar *data; - struct st_page *pages, *syncing, *active, *pool, *pool_last; + struct st_page *pages, *syncing, *active, *pool, **pool_last_ptr; /* note that, e.g. LOCK_active is only used to protect 'active' pointer, to protect the content of the active page diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 0fda3f73c9c..ab4e696c21c 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -10943,6 +10943,13 @@ int QUICK_RANGE_SELECT::reset() DBUG_ENTER("QUICK_RANGE_SELECT::reset"); last_range= NULL; cur_range= (QUICK_RANGE**) ranges.buffer; + + if (file->inited == handler::RND) + { + /* Handler could be left in this state by MRR */ + if ((error= file->ha_rnd_end())) + DBUG_RETURN(error); + } if (file->inited == handler::NONE) { diff --git a/sql/sp_head.cc b/sql/sp_head.cc index f3ba0073c69..0d92a68a2d4 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3113,8 +3113,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) (the order of query cache and subst_spvars calls is irrelevant because queries with SP vars can't be cached) */ - if (unlikely((thd->variables.option_bits & OPTION_LOG_OFF)==0)) - general_log_write(thd, COM_QUERY, thd->query(), thd->query_length()); + general_log_write(thd, COM_QUERY, thd->query(), thd->query_length()); if (query_cache_send_result_to_client(thd, thd->query(), thd->query_length()) <= 0) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 8f27c45247e..b8e7d891e05 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1633,14 +1633,20 @@ ulong acl_get(const char *host, const char *ip, acl_entry *entry; DBUG_ENTER("acl_get"); - mysql_mutex_lock(&acl_cache->lock); - end=strmov((tmp_db=strmov(strmov(key, ip ? ip : "")+1,user)+1),db); + tmp_db= strmov(strmov(key, ip ? ip : "") + 1, user) + 1; + end= strnmov(tmp_db, db, key + sizeof(key) - tmp_db); + + if (end >= key + sizeof(key)) // db name was truncated + DBUG_RETURN(0); // no privileges for an invalid db name + if (lower_case_table_names) { my_casedn_str(files_charset_info, tmp_db); db=tmp_db; } key_length= (size_t) (end-key); + + mysql_mutex_lock(&acl_cache->lock); if (!db_is_pattern && (entry=(acl_entry*) acl_cache->search((uchar*) key, key_length))) { @@ -4954,11 +4960,17 @@ static bool check_grant_db_routine(THD *thd, const char *db, HASH *hash) bool check_grant_db(THD *thd,const char *db) { Security_context *sctx= thd->security_ctx; - char helping [SAFE_NAME_LEN + USERNAME_LENGTH+2]; + char helping [SAFE_NAME_LEN + USERNAME_LENGTH+2], *end; uint len; bool error= TRUE; - len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1; + end= strmov(helping, sctx->priv_user) + 1; + end= strnmov(end, db, helping + sizeof(helping) - end); + + if (end >= helping + sizeof(helping)) // db name was truncated + return 1; // no privileges for an invalid db name + + len= (uint) (end - helping) + 1; mysql_rwlock_rdlock(&LOCK_grant); diff --git a/sql/sql_audit.h b/sql/sql_audit.h index 51c695d091d..b2ce31f1d26 100644 --- a/sql/sql_audit.h +++ b/sql/sql_audit.h @@ -37,8 +37,16 @@ extern void mysql_audit_acquire_plugins(THD *thd, uint event_class); #ifndef EMBEDDED_LIBRARY extern void mysql_audit_notify(THD *thd, uint event_class, uint event_subtype, ...); + +static inline bool mysql_audit_general_enabled() +{ + return mysql_global_audit_mask[0] & MYSQL_AUDIT_GENERAL_CLASSMASK; +} + #else -#define mysql_audit_notify(...) +static inline void mysql_audit_notify(THD *thd, uint event_class, + uint event_subtype, ...) { } +#define mysql_audit_general_enabled() 0 #endif extern void mysql_audit_release(THD *thd); @@ -72,8 +80,7 @@ void mysql_audit_general_log(THD *thd, time_t time, const char *cmd, uint cmdlen, const char *query, uint querylen) { -#ifndef EMBEDDED_LIBRARY - if (mysql_global_audit_mask[0] & MYSQL_AUDIT_GENERAL_CLASSMASK) + if (mysql_audit_general_enabled()) { CHARSET_INFO *clientcs= thd ? thd->variables.character_set_client : global_system_variables.character_set_client; @@ -82,7 +89,6 @@ void mysql_audit_general_log(THD *thd, time_t time, 0, time, user, userlen, cmd, cmdlen, query, querylen, clientcs, 0); } -#endif } /** @@ -101,8 +107,7 @@ static inline void mysql_audit_general(THD *thd, uint event_subtype, int error_code, const char *msg) { -#ifndef EMBEDDED_LIBRARY - if (mysql_global_audit_mask[0] & MYSQL_AUDIT_GENERAL_CLASSMASK) + if (mysql_audit_general_enabled()) { time_t time= my_time(0); uint msglen= msg ? strlen(msg) : 0; @@ -130,7 +135,6 @@ void mysql_audit_general(THD *thd, uint event_subtype, error_code, time, user, userlen, msg, msglen, query.str(), query.length(), query.charset(), rows); } -#endif } #define MYSQL_AUDIT_NOTIFY_CONNECTION_CONNECT(thd) mysql_audit_notify(\ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 20092da994b..9c997cac637 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8909,7 +8909,9 @@ fill_record(THD * thd, List &fields, List &values, /* Update virtual fields*/ thd->abort_on_warning= FALSE; if (vcol_table && vcol_table->vfield && - update_virtual_fields(thd, vcol_table, TRUE)) + update_virtual_fields(thd, vcol_table, + vcol_table->triggers ? VCOL_UPDATE_ALL : + VCOL_UPDATE_FOR_WRITE)) goto err; thd->abort_on_warning= save_abort_on_warning; thd->no_errors= save_no_errors; @@ -8973,7 +8975,9 @@ fill_record_n_invoke_before_triggers(THD *thd, List &fields, if (item_field && item_field->field && (table= item_field->field->table) && table->vfield) - result= update_virtual_fields(thd, table, TRUE); + result= update_virtual_fields(thd, table, + table->triggers ? VCOL_UPDATE_ALL : + VCOL_UPDATE_FOR_WRITE); } } return result; @@ -9057,7 +9061,10 @@ fill_record(THD *thd, Field **ptr, List &values, bool ignore_errors, } /* Update virtual fields*/ thd->abort_on_warning= FALSE; - if (table->vfield && update_virtual_fields(thd, table, TRUE)) + if (table->vfield && + update_virtual_fields(thd, table, + table->triggers ? VCOL_UPDATE_ALL : + VCOL_UPDATE_FOR_WRITE)) goto err; thd->abort_on_warning= abort_on_warning_saved; DBUG_RETURN(thd->is_error()); @@ -9110,7 +9117,9 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr, { TABLE *table= (*ptr)->table; if (table->vfield) - result= update_virtual_fields(thd, table, TRUE); + result= update_virtual_fields(thd, table, + table->triggers ? VCOL_UPDATE_ALL : + VCOL_UPDATE_FOR_WRITE); } return result; diff --git a/sql/sql_base.h b/sql/sql_base.h index 698c4a012e7..71b4a9289ce 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -306,7 +306,8 @@ TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db, bool no_error); void mark_tmp_table_for_reuse(TABLE *table); bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists); -int update_virtual_fields(THD *thd, TABLE *table, bool ignore_stored= FALSE); +int update_virtual_fields(THD *thd, TABLE *table, + enum enum_vcol_update_mode vcol_update_mode= VCOL_UPDATE_FOR_READ); int dynamic_column_error_message(enum_dyncol_func_result rc); /* open_and_lock_tables with optional derived handling */ diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index c85cc86ccfd..2dd090578a7 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -329,7 +329,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ! thd->is_error()) { if (table->vfield) - update_virtual_fields(thd, table); + update_virtual_fields(thd, table, + table->triggers ? VCOL_UPDATE_ALL : + VCOL_UPDATE_FOR_READ); thd->examined_row_count++; // thd->is_error() is tested to disallow delete row on error if (!select || select->skip_record(thd) > 0) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 3c3b9f85727..231671d172b 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1677,9 +1677,10 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) } } key_copy((uchar*) key,table->record[0],table->key_info+key_nr,0); + key_part_map keypart_map= (1 << table->key_info[key_nr].key_parts) - 1; if ((error= (table->file->ha_index_read_idx_map(table->record[1], key_nr, (uchar*) key, - HA_WHOLE_KEY, + keypart_map, HA_READ_KEY_EXACT)))) goto err; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d2eb6ae8d1f..5dac052b749 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6717,8 +6717,10 @@ void sql_kill(THD *thd, ulong id, killed_state state) uint error; if (!(error= kill_one_thread(thd, id, state))) { - if (! thd->killed) + if ((!thd->killed)) my_ok(thd); + else + my_error(killed_errno(thd->killed), MYF(0), id); } else my_error(error, MYF(0), id); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 114de41f83a..c1f07581106 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2505,14 +2505,24 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) */ if (sl->prep_where) { - sl->where= sl->prep_where->copy_andor_structure(thd); + /* + We need this rollback because memory allocated in + copy_andor_structure() will be freed + */ + thd->change_item_tree((Item**)&sl->where, + sl->prep_where->copy_andor_structure(thd)); sl->where->cleanup(); } else sl->where= NULL; if (sl->prep_having) { - sl->having= sl->prep_having->copy_andor_structure(thd); + /* + We need this rollback because memory allocated in + copy_andor_structure() will be freed + */ + thd->change_item_tree((Item**)&sl->having, + sl->prep_having->copy_andor_structure(thd)); sl->having->cleanup(); } else diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 218b9b440b8..fcb650b4757 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1233,11 +1233,9 @@ JOIN::optimize() DBUG_RETURN(1); // error == -1 } if (const_table_map != found_const_table_map && - !(select_options & SELECT_DESCRIBE) && - (!conds || - !(conds->used_tables() & RAND_TABLE_BIT) || - select_lex->master_unit() == &thd->lex->unit)) // upper level SELECT + !(select_options & SELECT_DESCRIBE)) { + // There is at least one empty const table zero_result_cause= "no matching row in const table"; DBUG_PRINT("error",("Error: %s", zero_result_cause)); error= 0; @@ -5380,7 +5378,8 @@ best_access_path(JOIN *join, !ref_or_null_part) { /* use eq key */ max_key_part= (uint) ~0; - if ((key_flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME) + if ((key_flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME || + test(key_flags & HA_EXT_NOSAME)) { tmp = prev_record_reads(join->positions, idx, found_ref); records=1.0; @@ -7969,18 +7968,23 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, *ref_key=0; // end_marker if (j->type == JT_FT) DBUG_RETURN(0); + ulong key_flags= j->table->actual_key_flags(keyinfo); if (j->type == JT_CONST) j->table->const_table= 1; - else if (((j->table->actual_key_flags(keyinfo) & - (HA_NOSAME | HA_NULL_PART_KEY)) - != HA_NOSAME) || + else if (((key_flags & (HA_NOSAME | HA_NULL_PART_KEY))!= HA_NOSAME) || keyparts != j->table->actual_n_key_parts(keyinfo) || null_ref_key) { - /* Must read with repeat */ - j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF; - j->ref.null_ref_key= null_ref_key; - j->ref.null_ref_part= null_ref_part; + if (test(key_flags & HA_EXT_NOSAME) && keyparts == keyinfo->ext_key_parts && + !null_ref_key) + j->type= JT_EQ_REF; + else + { + /* Must read with repeat */ + j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF; + j->ref.null_ref_key= null_ref_key; + j->ref.null_ref_part= null_ref_part; + } } else if (keyuse_uses_no_tables) { @@ -9140,7 +9144,7 @@ void JOIN::drop_unused_derived_keys() JOIN_TAB *tab; for (tab= first_linear_tab(this, WITHOUT_CONST_TABLES); tab; - tab= next_linear_tab(this, tab, WITHOUT_BUSH_ROOTS)) + tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS)) { TABLE *table=tab->table; @@ -10606,9 +10610,22 @@ void JOIN::cleanup(bool full) if (full) { + JOIN_TAB *sort_tab= first_linear_tab(this, WITHOUT_CONST_TABLES); + if (pre_sort_join_tab) + { + if (sort_tab && sort_tab->select == pre_sort_join_tab->select) + { + pre_sort_join_tab->select= NULL; + } + else + clean_pre_sort_join_tab(); + } + for (tab= first_linear_tab(this, WITH_CONST_TABLES); tab; tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS)) + { tab->cleanup(); + } } else { @@ -16488,6 +16505,17 @@ int safe_index_read(JOIN_TAB *tab) } +/** + Reads content of constant table + + @param tab table + @param pos position of table in query plan + + @retval 0 ok, one row was found or one NULL-complemented row was created + @retval -1 ok, no row was found and no NULL-complemented row was created + @retval 1 error +*/ + static int join_read_const_table(JOIN_TAB *tab, POSITION *pos) { @@ -16606,6 +16634,16 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) } +/** + Read a constant table when there is at most one matching row, using a table + scan. + + @param tab Table to read + + @retval 0 Row was found + @retval -1 Row was not found + @retval 1 Got an error (other than row not found) during read +*/ static int join_read_system(JOIN_TAB *tab) { @@ -16638,12 +16676,9 @@ join_read_system(JOIN_TAB *tab) @param tab Table to read - @retval - 0 Row was found - @retval - -1 Row was not found - @retval - 1 Got an error (other than row not found) during read + @retval 0 Row was found + @retval -1 Row was not found + @retval 1 Got an error (other than row not found) during read */ static int @@ -18478,15 +18513,18 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, */ if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE || - quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT || + quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT || quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION || quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) - goto use_filesort; - ref_key= select->quick->index; - ref_key_parts= select->quick->used_key_parts; + ref_key= MAX_KEY; + else + { + ref_key= select->quick->index; + ref_key_parts= select->quick->used_key_parts; + } } - if (ref_key >= 0) + if (ref_key >= 0 && ref_key != MAX_KEY) { /* We come here when there is a REF key. @@ -18858,6 +18896,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, TABLE *table; SQL_SELECT *select; JOIN_TAB *tab; + int err= 0; + bool quick_created= FALSE; DBUG_ENTER("create_sort_index"); if (join->table_count == join->const_tables) @@ -18865,18 +18905,61 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, tab= join->join_tab + join->const_tables; table= tab->table; select= tab->select; + + JOIN_TAB *save_pre_sort_join_tab= NULL; + if (join->pre_sort_join_tab) + { + /* + we've already been in this function, and stashed away the original access + method in join->pre_sort_join_tab, restore it now. + */ + + /* First, restore state of the handler */ + if (join->pre_sort_index != MAX_KEY) + { + if (table->file->ha_index_or_rnd_end()) + goto err; + if (join->pre_sort_idx_pushed_cond) + { + table->file->idx_cond_push(join->pre_sort_index, + join->pre_sort_idx_pushed_cond); + } + } + else + { + if (table->file->ha_index_or_rnd_end() || + table->file->ha_rnd_init(TRUE)) + goto err; + } + + /* Second, restore access method parameters */ + tab->records= join->pre_sort_join_tab->records; + tab->select= join->pre_sort_join_tab->select; + tab->select_cond= join->pre_sort_join_tab->select_cond; + tab->type= join->pre_sort_join_tab->type; + tab->read_first_record= join->pre_sort_join_tab->read_first_record; + + save_pre_sort_join_tab= join->pre_sort_join_tab; + join->pre_sort_join_tab= NULL; + } + else + { + /* + Save index #, save index condition. Do it right now, because MRR may + */ + if (table->file->inited == handler::INDEX) + { + join->pre_sort_index= table->file->active_index; + join->pre_sort_idx_pushed_cond= table->file->pushed_idx_cond; + // no need to save key_read + } + else + join->pre_sort_index= MAX_KEY; + } /* Currently ORDER BY ... LIMIT is not supported in subqueries. */ DBUG_ASSERT(join->group_list || !join->is_in_subquery()); - /* - If we have a select->quick object that is created outside of - create_sort_index() and this is part of a subquery that - potentially can be executed multiple times then we should not - delete the quick object on exit from this function. - */ - bool keep_quick= select && select->quick && join->join_tab_save; - /* When there is SQL_BIG_RESULT do not sort using index for GROUP BY, and thus force sorting on disk unless a group min-max optimization @@ -18928,7 +19011,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, get_quick_select_for_ref(thd, table, &tab->ref, tab->found_records)))) goto err; - DBUG_ASSERT(!keep_quick); + quick_created= TRUE; } } @@ -18944,7 +19027,27 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, table->sort.found_records=filesort(thd, table,join->sortorder, length, select, filesort_limit, 0, &examined_rows); + + if (quick_created) + { + /* This will delete the quick select. */ + select->cleanup(); + } + + if (!join->pre_sort_join_tab) + { + if (save_pre_sort_join_tab) + join->pre_sort_join_tab= save_pre_sort_join_tab; + else if (!(join->pre_sort_join_tab= (JOIN_TAB*)thd->alloc(sizeof(JOIN_TAB)))) + goto err; + } + + *(join->pre_sort_join_tab)= *tab; + + /*TODO: here, close the index scan, cancel index-only read. */ tab->records= table->sort.found_records; // For SQL_CALC_ROWS +#if 0 + /* MariaDB doesn't need the following: */ if (select) { /* @@ -18961,6 +19064,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, tablesort_result_cache= table->sort.io_cache; table->sort.io_cache= NULL; + // select->cleanup(); // filesort did select /* If a quick object was created outside of create_sort_index() that might be reused, then do not call select->cleanup() since @@ -18983,18 +19087,61 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, // Restore the output resultset table->sort.io_cache= tablesort_result_cache; } +#endif + tab->select=NULL; tab->set_select_cond(NULL, __LINE__); - tab->last_inner= 0; - tab->first_unmatched= 0; tab->type=JT_ALL; // Read with normal read_record tab->read_first_record= join_init_read_record; + tab->table->file->ha_index_or_rnd_end(); + + if (err) + goto err; + tab->join->examined_rows+=examined_rows; - table->disable_keyread(); // Restore if we used indexes DBUG_RETURN(table->sort.found_records == HA_POS_ERROR); err: DBUG_RETURN(-1); } + +void JOIN::clean_pre_sort_join_tab() +{ + //TABLE *table= pre_sort_join_tab->table; + /* + Note: we can come here for fake_select_lex object. That object will have + the table already deleted by st_select_lex_unit::cleanup(). + We rely on that fake_select_lex didn't have quick select. + */ +#if 0 + if (pre_sort_join_tab->select && pre_sort_join_tab->select->quick) + { + /* + We need to preserve tablesort's output resultset here, because + QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT (called by + SQL_SELECT::cleanup()) may free it assuming it's the result of the quick + select operation that we no longer need. Note that all the other parts of + this data structure are cleaned up when + QUICK_INDEX_MERGE_SELECT::get_next encounters end of data, so the next + SQL_SELECT::cleanup() call changes sort.io_cache alone. + */ + IO_CACHE *tablesort_result_cache; + + tablesort_result_cache= table->sort.io_cache; + table->sort.io_cache= NULL; + pre_sort_join_tab->select->cleanup(); + table->quick_keys.clear_all(); // as far as we cleanup select->quick + table->intersect_keys.clear_all(); + table->sort.io_cache= tablesort_result_cache; + } +#endif + //table->disable_keyread(); // Restore if we used indexes + if (pre_sort_join_tab->select && pre_sort_join_tab->select->quick) + { + pre_sort_join_tab->select->cleanup(); + } +} + + /***************************************************************************** Remove duplicates from tmp table This should be recoded to add a unique index to the table and remove @@ -20474,40 +20621,66 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, res_selected_fields.empty(); res_all_fields.empty(); - uint i, border= all_fields.elements - elements; - for (i= 0; (item= it++); i++) + uint border= all_fields.elements - elements; + for (uint i= 0; (item= it++); i++) { Field *field; - - if ((item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) || - (item->type() == Item::FUNC_ITEM && - ((Item_func*)item)->functype() == Item_func::SUSERVAR_FUNC)) + if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) item_field= item; - else + else if (item->type() == Item::FIELD_ITEM) + item_field= item->get_tmp_table_item(thd); + else if (item->type() == Item::FUNC_ITEM && + ((Item_func*)item)->functype() == Item_func::SUSERVAR_FUNC) { - if (item->type() == Item::FIELD_ITEM) + field= item->get_tmp_table_field(); + if (field != NULL) { - item_field= item->get_tmp_table_item(thd); + /* + Replace "@:=" with "@:=". Otherwise, + we would re-evaluate , and if expression were + a subquery, this would access already-unlocked tables. + */ + Item_func_set_user_var* suv= + new Item_func_set_user_var((Item_func_set_user_var*) item); + Item_field *new_field= new Item_field(field); + if (!suv || !new_field || suv->fix_fields(thd, (Item**)&suv)) + DBUG_RETURN(true); // Fatal error + ((Item *)suv)->name= item->name; + /* + We are replacing the argument of Item_func_set_user_var after its + value has been read. The argument's null_value should be set by + now, so we must set it explicitly for the replacement argument + since the null_value may be read without any preceeding call to + val_*(). + */ + new_field->update_null_value(); + List list; + list.push_back(new_field); + suv->set_arguments(list); + item_field= suv; } - else if ((field= item->get_tmp_table_field())) - { - if (item->type() == Item::SUM_FUNC_ITEM && field->table->group) - item_field= ((Item_sum*) item)->result_item(field); - else - item_field= (Item*) new Item_field(field); - if (!item_field) - DBUG_RETURN(TRUE); // Fatal error + else + item_field= item; + } + else if ((field= item->get_tmp_table_field())) + { + if (item->type() == Item::SUM_FUNC_ITEM && field->table->group) + item_field= ((Item_sum*) item)->result_item(field); + else + item_field= (Item*) new Item_field(field); + if (!item_field) + DBUG_RETURN(true); // Fatal error - if (item->real_item()->type() != Item::FIELD_ITEM) - field->orig_table= 0; - item_field->name= item->name; - if (item->type() == Item::REF_ITEM) - { - Item_field *ifield= (Item_field *) item_field; - Item_ref *iref= (Item_ref *) item; - ifield->table_name= iref->table_name; - ifield->db_name= iref->db_name; - } + if (item->real_item()->type() != Item::FIELD_ITEM) + field->orig_table= 0; + item_field->name= item->name; + if (item->type() == Item::REF_ITEM) + { + Item_field *ifield= (Item_field *) item_field; + Item_ref *iref= (Item_ref *) item; + ifield->table_name= iref->table_name; + ifield->db_name= iref->db_name; + } #ifndef DBUG_OFF if (!item_field->name) { @@ -20519,20 +20692,20 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, item_field->name= sql_strmake(str.ptr(),str.length()); } #endif - } - else - item_field= item; } + else + item_field= item; + res_all_fields.push_back(item_field); ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]= item_field; } List_iterator_fast itr(res_all_fields); - for (i= 0; i < border; i++) + for (uint i= 0; i < border; i++) itr++; itr.sublist(res_selected_fields, elements); - DBUG_RETURN(FALSE); + DBUG_RETURN(false); } @@ -22712,6 +22885,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table, ha_rows table_records= table->stat_records(); bool group= join && join->group && order == join->group_list; ha_rows ref_key_quick_rows= HA_POS_ERROR; + const bool has_limit= (select_limit_arg != HA_POS_ERROR); /* If not used with LIMIT, only use keys if the whole query can be @@ -22736,7 +22910,8 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table, else keys= usable_keys; - if (ref_key >= 0 && table->covering_keys.is_set(ref_key)) + if (ref_key >= 0 && ref_key != MAX_KEY && + table->covering_keys.is_set(ref_key)) ref_key_quick_rows= table->quick_rows[ref_key]; if (join) @@ -22843,7 +23018,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table, be included into the result set. */ if (select_limit > table_records/rec_per_key) - select_limit= table_records; + select_limit= table_records; else select_limit= (ha_rows) (select_limit*rec_per_key); } /* group */ @@ -22925,7 +23100,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table, *new_key= best_key; *new_key_direction= best_key_direction; - *new_select_limit= best_select_limit; + *new_select_limit= has_limit ? best_select_limit : table_records; if (new_used_key_parts != NULL) *new_used_key_parts= best_key_parts; diff --git a/sql/sql_select.h b/sql/sql_select.h index 118a684ab62..e4687b4f00c 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -897,6 +897,14 @@ protected: public: JOIN_TAB *join_tab, **best_ref; + + /* + Saved join_tab for pre_sorting. create_sort_index() will save here.. + */ + JOIN_TAB *pre_sort_join_tab; + uint pre_sort_index; + Item *pre_sort_idx_pushed_cond; + void clean_pre_sort_join_tab(); /* For "Using temporary+Using filesort" queries, JOIN::join_tab can point to @@ -1279,6 +1287,8 @@ public: outer_ref_cond= pseudo_bits_cond= NULL; in_to_exists_where= NULL; in_to_exists_having= NULL; + + pre_sort_join_tab= NULL; } int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num, diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 878faa189a2..19a25c28942 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3880,8 +3880,9 @@ end: /* Restore original LEX value, statement's arena and THD arena values. */ lex_end(thd->lex); - if (i_s_arena.free_list) - i_s_arena.free_items(); + // Free items, before restoring backup_arena below. + DBUG_ASSERT(i_s_arena.free_list == NULL); + thd->free_items(); /* For safety reset list of open temporary tables before closing diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b2052e7f85b..eb2a52e426c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7515,7 +7515,7 @@ copy_data_between_tables(THD *thd, TABLE *from,TABLE *to, } prev_insert_id= to->file->next_insert_id; if (to->vfield) - update_virtual_fields(thd, to, TRUE); + update_virtual_fields(thd, to, VCOL_UPDATE_FOR_WRITE); if (thd->is_error()) { error= 1; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index d8254c9dbdb..78b693c5237 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -560,7 +560,9 @@ int mysql_update(THD *thd, while (!(error=info.read_record(&info)) && !thd->killed) { if (table->vfield) - update_virtual_fields(thd, table); + update_virtual_fields(thd, table, + table->triggers ? VCOL_UPDATE_ALL : + VCOL_UPDATE_FOR_READ); thd->examined_row_count++; if (!select || (error= select->skip_record(thd)) > 0) { @@ -676,7 +678,9 @@ int mysql_update(THD *thd, while (!(error=info.read_record(&info)) && !thd->killed) { if (table->vfield) - update_virtual_fields(thd, table); + update_virtual_fields(thd, table, + table->triggers ? VCOL_UPDATE_ALL : + VCOL_UPDATE_FOR_READ); thd->examined_row_count++; if (!select || select->skip_record(thd) > 0) { diff --git a/sql/table.cc b/sql/table.cc index 6a6f9681471..194b037436d 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -988,7 +988,6 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, keyinfo->ext_key_part_map= 0; if (share->use_ext_keys && i) { - keyinfo->ext_key_flags= keyinfo->flags | HA_NOSAME; keyinfo->ext_key_part_map= 0; for (j= 0; j < first_key_parts && keyinfo->ext_key_parts < MAX_REF_PARTS; @@ -1009,7 +1008,9 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, keyinfo->ext_key_parts++; keyinfo->ext_key_part_map|= 1 << j; } - } + } + if (j == first_key_parts) + keyinfo->ext_key_flags= keyinfo->flags | HA_NOSAME | HA_EXT_NOSAME; } share->ext_key_parts+= keyinfo->ext_key_parts; } @@ -6425,22 +6426,25 @@ bool is_simple_order(ORDER *order) @param thd Thread handle @param table The TABLE object - @param for_write Requests to compute only fields needed for write + @param vcol_update_mode Specifies what virtual column are computed @details The function computes the values of the virtual columns of the table and stores them in the table record buffer. - Only fields from vcol_set are computed, and, when the flag for_write is not - set to TRUE, a virtual field is computed only if it's not stored. - The flag for_write is set to TRUE for row insert/update operations. - + If vcol_update_mode is set to VCOL_UPDATE_ALL then all virtual column are + computed. Otherwise, only fields from vcol_set are computed: all of them, + if vcol_update_mode is set to VCOL_UPDATE_FOR_WRITE, and, only those with + the stored_in_db flag set to false, if vcol_update_mode is equal to + VCOL_UPDATE_FOR_READ. + @retval 0 Success @retval >0 Error occurred when storing a virtual field value */ -int update_virtual_fields(THD *thd, TABLE *table, bool for_write) +int update_virtual_fields(THD *thd, TABLE *table, + enum enum_vcol_update_mode vcol_update_mode) { DBUG_ENTER("update_virtual_fields"); Field **vfield_ptr, *vfield; @@ -6453,9 +6457,9 @@ int update_virtual_fields(THD *thd, TABLE *table, bool for_write) { vfield= (*vfield_ptr); DBUG_ASSERT(vfield->vcol_info && vfield->vcol_info->expr_item); - /* Only update those fields that are marked in the vcol_set bitmap */ - if (bitmap_is_set(table->vcol_set, vfield->field_index) && - (for_write || !vfield->stored_in_db)) + if ((bitmap_is_set(table->vcol_set, vfield->field_index) && + (vcol_update_mode == VCOL_UPDATE_FOR_WRITE || !vfield->stored_in_db)) || + vcol_update_mode == VCOL_UPDATE_ALL) { /* Compute the actual value of the virtual fields */ error= vfield->vcol_info->expr_item->save_in_field(vfield, 0); diff --git a/sql/table.h b/sql/table.h index 0daa1947b52..bb0305f7924 100644 --- a/sql/table.h +++ b/sql/table.h @@ -300,6 +300,13 @@ enum tmp_table_type }; enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP }; +enum enum_vcol_update_mode +{ + VCOL_UPDATE_FOR_READ= 0, + VCOL_UPDATE_FOR_WRITE, + VCOL_UPDATE_ALL +}; + typedef struct st_filesort_info { IO_CACHE *io_cache; /* If sorted through filesort */ diff --git a/storage/heap/hp_rkey.c b/storage/heap/hp_rkey.c index d0cbb94eb0e..138d65f9d25 100644 --- a/storage/heap/hp_rkey.c +++ b/storage/heap/hp_rkey.c @@ -65,7 +65,7 @@ int heap_rkey(HP_INFO *info, uchar *record, int inx, const uchar *key, info->update= HA_STATE_NO_KEY; DBUG_RETURN(my_errno); } - if (!(keyinfo->flag & HA_NOSAME)) + if ((keyinfo->flag & (HA_NOSAME | HA_NULL_PART_KEY)) != HA_NOSAME) memcpy(info->lastkey, key, (size_t) keyinfo->length); } memcpy(record, pos, (size_t) share->reclength); diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index c9dc9e20072..a6fdff72f50 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -3263,6 +3263,7 @@ btr_compress( if (adjust) { nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor)); + ut_ad(nth_rec > 0); } /* Decide the page to which we try to merge and which will inherit @@ -3498,6 +3499,7 @@ func_exit: mem_heap_free(heap); if (adjust) { + ut_ad(nth_rec > 0); btr_cur_position( index, page_rec_get_nth(merge_block->frame, nth_rec), @@ -4011,8 +4013,22 @@ btr_index_page_validate( { page_cur_t cur; ibool ret = TRUE; +#ifndef DBUG_OFF + ulint nth = 1; +#endif /* !DBUG_OFF */ page_cur_set_before_first(block, &cur); + + /* Directory slot 0 should only contain the infimum record. */ + DBUG_EXECUTE_IF("check_table_rec_next", + ut_a(page_rec_get_nth_const( + page_cur_get_page(&cur), 0) + == cur.rec); + ut_a(page_dir_slot_get_n_owned( + page_dir_get_nth_slot( + page_cur_get_page(&cur), 0)) + == 1);); + page_cur_move_to_next(&cur); for (;;) { @@ -4026,6 +4042,16 @@ btr_index_page_validate( return(FALSE); } + /* Verify that page_rec_get_nth_const() is correctly + retrieving each record. */ + DBUG_EXECUTE_IF("check_table_rec_next", + ut_a(cur.rec == page_rec_get_nth_const( + page_cur_get_page(&cur), + page_rec_get_n_recs_before( + cur.rec))); + ut_a(nth++ == page_rec_get_n_recs_before( + cur.rec));); + page_cur_move_to_next(&cur); } diff --git a/storage/innobase/page/page0cur.c b/storage/innobase/page/page0cur.c index d49b121afab..55ba72b4fe9 100644 --- a/storage/innobase/page/page0cur.c +++ b/storage/innobase/page/page0cur.c @@ -1902,6 +1902,7 @@ page_cur_delete_rec( /* Save to local variables some data associated with current_rec */ cur_slot_no = page_dir_find_owner_slot(current_rec); + ut_ad(cur_slot_no > 0); cur_dir_slot = page_dir_get_nth_slot(page, cur_slot_no); cur_n_owned = page_dir_slot_get_n_owned(cur_dir_slot); diff --git a/storage/innobase/page/page0page.c b/storage/innobase/page/page0page.c index 946ec0e1c43..78135b0aff2 100644 --- a/storage/innobase/page/page0page.c +++ b/storage/innobase/page/page0page.c @@ -796,8 +796,8 @@ zip_reorganize: /* Before copying, "ret" was the predecessor of the predefined supremum record. If it was the predefined infimum record, then it would - still be the infimum. Thus, the assertion - ut_a(ret_pos > 0) would fail here. */ + still be the infimum, and we would have + ret_pos == 0. */ if (UNIV_UNLIKELY (!page_zip_reorganize(new_block, index, mtr))) { @@ -1052,6 +1052,7 @@ page_delete_rec_list_end( n_owned = rec_get_n_owned_new(rec2) - count; slot_index = page_dir_find_owner_slot(rec2); + ut_ad(slot_index > 0); slot = page_dir_get_nth_slot(page, slot_index); } else { rec_t* rec2 = rec; @@ -1067,6 +1068,7 @@ page_delete_rec_list_end( n_owned = rec_get_n_owned_old(rec2) - count; slot_index = page_dir_find_owner_slot(rec2); + ut_ad(slot_index > 0); slot = page_dir_get_nth_slot(page, slot_index); } @@ -1471,6 +1473,10 @@ page_rec_get_nth_const( ulint n_owned; const rec_t* rec; + if (nth == 0) { + return(page_get_infimum_rec(page)); + } + ut_ad(nth < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1)); for (i = 0;; i++) { diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 785fe5d8226..1278d951a16 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -2484,9 +2484,10 @@ int ha_maria::info(uint flag) errkey= maria_info.errkey; my_store_ptr(dup_ref, ref_length, maria_info.dup_key_pos); } - /* Faster to always update, than to do it based on flag */ - stats.update_time= maria_info.update_time; - stats.auto_increment_value= maria_info.auto_increment; + if (flag & HA_STATUS_TIME) + stats.update_time= maria_info.update_time; + if (flag & HA_STATUS_AUTO) + stats.auto_increment_value= maria_info.auto_increment; return 0; } diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index 8e0407c9d7a..71faa11fd2b 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -4669,7 +4669,7 @@ int _ma_read_block_record2(MARIA_HA *info, uchar *record, uchar *data, uchar *end_of_data) { MARIA_SHARE *share= info->s; - uchar *UNINIT_VAR(field_length_data), *blob_buffer, *start_of_data; + uchar *UNINIT_VAR(field_length_data), *UNINIT_VAR(blob_buffer), *start_of_data; uint flag, null_bytes, cur_null_bytes, row_extents, field_lengths; my_bool found_blob= 0; MARIA_EXTENT_CURSOR extent; @@ -4677,8 +4677,6 @@ int _ma_read_block_record2(MARIA_HA *info, uchar *record, MARIA_ROW *cur_row= &info->cur_row; DBUG_ENTER("_ma_read_block_record2"); - LINT_INIT(blob_buffer); - start_of_data= data; flag= (uint) (uchar) data[0]; cur_null_bytes= share->base.original_null_bytes; @@ -5106,6 +5104,7 @@ int _ma_read_block_record(MARIA_HA *info, uchar *record, uchar *data, *end_of_data, *buff; uint offset; uint block_size= share->block_size; + int ret; DBUG_ENTER("_ma_read_block_record"); DBUG_PRINT("enter", ("rowid: %lu page: %lu rownr: %u", (ulong) record_pos, @@ -5127,7 +5126,8 @@ int _ma_read_block_record(MARIA_HA *info, uchar *record, my_errno= HA_ERR_RECORD_DELETED; /* File crashed */ DBUG_RETURN(HA_ERR_RECORD_DELETED); } - DBUG_RETURN(_ma_read_block_record2(info, record, data, end_of_data)); + ret= _ma_read_block_record2(info, record, data, end_of_data); + DBUG_RETURN(ret); } diff --git a/storage/maria/ma_rrnd.c b/storage/maria/ma_rrnd.c index 24c4bfdd467..8c35c71c95e 100644 --- a/storage/maria/ma_rrnd.c +++ b/storage/maria/ma_rrnd.c @@ -30,6 +30,7 @@ int maria_rrnd(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos) { + int ret; DBUG_ENTER("maria_rrnd"); DBUG_ASSERT(filepos != HA_OFFSET_ERROR); @@ -40,5 +41,6 @@ int maria_rrnd(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos) DBUG_RETURN(my_errno); info->cur_row.lastpos= filepos; /* Remember for update */ - DBUG_RETURN((*info->s->read_record)(info, buf, filepos)); + ret= (*info->s->read_record)(info, buf, filepos); + DBUG_RETURN(ret); } diff --git a/storage/maria/ma_test2.c b/storage/maria/ma_test2.c index 5d0882f3fcb..ea1978b4ee5 100644 --- a/storage/maria/ma_test2.c +++ b/storage/maria/ma_test2.c @@ -50,7 +50,7 @@ static ulong pagecache_size=8192*32; static enum data_file_type record_type= DYNAMIC_RECORD; static uint keys=MARIA_KEYS,recant=1000; -static uint16 key1[1001],key3[5000]; +static uint16 key1[1001],key3[5001]; static uchar record[300],record2[300],key[100],key2[100]; static uchar read_record[300],read_record2[300],read_record3[300]; static HA_KEYSEG glob_keyseg[MARIA_KEYS][MAX_PARTS]; @@ -222,7 +222,7 @@ int main(int argc, char *argv[]) blob_buffer=0; for (i=1000 ; i>0 ; i--) key1[i]=0; - for (i=4999 ; i>0 ; i--) key3[i]=0; + for (i=5000 ; i>0 ; i--) key3[i]=0; if (!silent) printf("- Creating maria-file\n"); @@ -280,7 +280,7 @@ int main(int argc, char *argv[]) if (key3[n3] == 1 && first_key <3 && first_key+keys >= 3) { printf("Error: Didn't get error when writing second key: '%8d'\n",n3); - goto err; + goto err2; } write_count++; key1[n1]++; key3[n3]=1; } @@ -341,7 +341,7 @@ int main(int argc, char *argv[]) key, keyinfo[0].seg[0].length)) { printf("Found wrong record when searching for key: \"%s\"\n",key); - goto err; + goto err2; } if (opt_delete == (uint) remove_count) /* While testing */ goto end; @@ -394,7 +394,7 @@ int main(int argc, char *argv[]) printf("Found wrong record when searching for key: \"%s\"; Found \"%.*s\"\n", key, keyinfo[0].seg[0].length, read_record+keyinfo[0].seg[0].start); - goto err; + goto err2; } if (use_blob) { @@ -455,7 +455,7 @@ int main(int argc, char *argv[]) if (memcmp(read_record,read_record2,reclength) != 0) { printf("maria_rsame didn't find same record\n"); - goto err; + goto err2; } info.recpos=maria_position(file); if (maria_rfirst(file,read_record2,0) || @@ -463,7 +463,7 @@ int main(int argc, char *argv[]) memcmp(read_record,read_record2,reclength) != 0) { printf("maria_rsame_with_pos didn't find same record\n"); - goto err; + goto err2; } { int skr; @@ -484,7 +484,7 @@ int main(int argc, char *argv[]) if (ant != dupp_keys) { printf("next: Found: %d keys of %d\n",ant,dupp_keys); - goto err; + goto err2; } ant=0; while (maria_rprev(file,read_record3,0) == 0 && @@ -492,7 +492,7 @@ int main(int argc, char *argv[]) if (ant != dupp_keys) { printf("prev: Found: %d records of %d\n",ant,dupp_keys); - goto err; + goto err2; } /* Check of maria_rnext_same */ @@ -504,7 +504,7 @@ int main(int argc, char *argv[]) if (ant != dupp_keys || my_errno != HA_ERR_END_OF_FILE) { printf("maria_rnext_same: Found: %d records of %d\n",ant,dupp_keys); - goto err; + goto err2; } } @@ -531,7 +531,7 @@ int main(int argc, char *argv[]) printf("Can't find last record\n"); DBUG_DUMP("record2", read_record2, reclength); DBUG_DUMP("record3", read_record3, reclength); - goto err; + goto err2; } ant=1; while (maria_rprev(file,read_record3,0) == 0 && ant < write_count+10) @@ -539,12 +539,12 @@ int main(int argc, char *argv[]) if (ant != write_count - opt_delete) { printf("prev: I found: %d records of %d\n",ant,write_count); - goto err; + goto err2; } if (bcmp(read_record,read_record3,reclength)) { printf("Can't find first record\n"); - goto err; + goto err2; } if (!silent) @@ -585,7 +585,7 @@ int main(int argc, char *argv[]) if (bcmp(read_record+start,key,(uint) i)) { puts("Didn't find right record"); - goto err; + goto err2; } } #endif @@ -605,7 +605,7 @@ int main(int argc, char *argv[]) if (ant != dupp_keys-1) { printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-1); - goto err; + goto err2; } } if (dupp_keys>4) @@ -623,7 +623,7 @@ int main(int argc, char *argv[]) if (ant != dupp_keys-2) { printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-2); - goto err; + goto err2; } } if (dupp_keys > 6) @@ -643,7 +643,7 @@ int main(int argc, char *argv[]) if (ant != dupp_keys-3) { printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-3); - goto err; + goto err2; } if (!silent) @@ -658,7 +658,7 @@ int main(int argc, char *argv[]) if (ant != dupp_keys-4) { printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-4); - goto err; + goto err2; } } @@ -687,7 +687,7 @@ int main(int argc, char *argv[]) if (i != write_count && i != write_count - opt_delete) { printf("Found wrong number of rows while scanning table\n"); - goto err; + goto err2; } if (maria_rsame_with_pos(file,read_record,0,info.recpos)) @@ -695,7 +695,7 @@ int main(int argc, char *argv[]) if (bcmp(read_record,read_record2,reclength) != 0) { printf("maria_rsame_with_pos didn't find same record\n"); - goto err; + goto err2; } for (i=min(2,keys) ; i-- > 0 ;) @@ -704,7 +704,7 @@ int main(int argc, char *argv[]) if (bcmp(read_record,read_record2,reclength) != 0) { printf("maria_rsame didn't find same record\n"); - goto err; + goto err2; } } if (!silent) @@ -731,7 +731,7 @@ int main(int argc, char *argv[]) { printf("maria_records_range returned %ld; Should be about %ld\n", (long) range_records,(long) info.records); - goto err; + goto err2; } if (verbose) { @@ -768,7 +768,7 @@ int main(int argc, char *argv[]) { printf("maria_records_range for key: %d returned %lu; Should be about %lu\n", i, (ulong) range_records, (ulong) records); - goto err; + goto err2; } if (verbose && records) { @@ -783,13 +783,13 @@ int main(int argc, char *argv[]) if (!silent) printf("- maria_info\n"); maria_status(file,&info,HA_STATUS_VARIABLE | HA_STATUS_CONST); - if (info.records != write_count-opt_delete || info.deleted > opt_delete + update - || info.keys != keys) + if (info.records != write_count-opt_delete || + info.deleted > opt_delete + update || info.keys != keys) { puts("Wrong info from maria_info"); printf("Got: records: %lu delete: %lu i_keys: %d\n", (ulong) info.records, (ulong) info.deleted, info.keys); - goto err; + goto err2; } if (verbose) { @@ -828,7 +828,7 @@ int main(int argc, char *argv[]) printf("scan with cache: I can only find: %d records of %d\n", ant,write_count-opt_delete); maria_scan_end(file); - goto err; + goto err2; } if (maria_extra(file,HA_EXTRA_NO_CACHE,0)) { @@ -848,7 +848,7 @@ int main(int argc, char *argv[]) printf("scan with cache: I can only find: %d records of %d\n", ant,write_count-opt_delete); maria_scan_end(file); - goto err; + goto err2; } maria_scan_end(file); @@ -872,7 +872,7 @@ int main(int argc, char *argv[]) { printf("maria_rrnd didn't advance filepointer; old: %ld, new: %ld\n", (long) lastpos, (long) info.recpos); - goto err; + goto err2; } lastpos=info.recpos; if (error == 0) @@ -897,7 +897,7 @@ int main(int argc, char *argv[]) printf("Found blob with wrong info at %ld\n",(long) lastpos); maria_scan_end(file); my_errno= 0; - goto err; + goto err2; } } } @@ -920,7 +920,7 @@ int main(int argc, char *argv[]) printf("Deleted only %d of %d records (%d parts)\n",opt_delete,write_count, found_parts); maria_scan_end(file); - goto err; + goto err2; } if (testflag == 6) goto end; @@ -1021,10 +1021,11 @@ reads: %10lu\n", return(0); err: printf("got error: %d when using MARIA-database\n",my_errno); +err2: if (file) { if (maria_commit(file)) - goto err; + printf("got error: %d when using MARIA-database\n",my_errno); maria_close(file); } maria_end(); diff --git a/storage/pbxt/mysql-test/main/r/rpl_mmap.result b/storage/pbxt/mysql-test/main/r/rpl_mmap.result new file mode 100644 index 00000000000..b1f5f15d012 --- /dev/null +++ b/storage/pbxt/mysql-test/main/r/rpl_mmap.result @@ -0,0 +1,16 @@ +include/master-slave.inc +[connection master] +create table t1 (a int) engine=InnoDB; +create table t2 (a int) engine=pbxt; +begin; +insert into t1 values (1); +insert into t2 values (2); +commit; +select * from t1; +a +1 +select * from t2; +a +2 +drop table t1, t2; +include/rpl_end.inc diff --git a/storage/pbxt/mysql-test/main/t/rpl_mmap.test b/storage/pbxt/mysql-test/main/t/rpl_mmap.test new file mode 100644 index 00000000000..a6f50e1b6b3 --- /dev/null +++ b/storage/pbxt/mysql-test/main/t/rpl_mmap.test @@ -0,0 +1,21 @@ +--source include/have_innodb.inc +--source include/master-slave.inc + +create table t1 (a int) engine=InnoDB; +create table t2 (a int) engine=pbxt; + +begin; +insert into t1 values (1); +insert into t2 values (2); +commit; + +sync_slave_with_master; +connection slave; + +select * from t1; +select * from t2; + +connection master; +drop table t1, t2; + +--source include/rpl_end.inc diff --git a/storage/xtradb/btr/btr0btr.c b/storage/xtradb/btr/btr0btr.c index 3f11684cb34..ed97fc5bd58 100644 --- a/storage/xtradb/btr/btr0btr.c +++ b/storage/xtradb/btr/btr0btr.c @@ -1891,6 +1891,7 @@ btr_root_raise_and_insert( root = btr_cur_get_page(cursor); root_block = btr_cur_get_block(cursor); root_page_zip = buf_block_get_page_zip(root_block); + ut_ad(page_get_n_recs(root) > 0); #ifdef UNIV_ZIP_DEBUG ut_a(!root_page_zip || page_zip_validate(root_page_zip, root)); #endif /* UNIV_ZIP_DEBUG */ @@ -2371,12 +2372,20 @@ btr_insert_on_non_leaf_level_func( BTR_CONT_MODIFY_TREE, &cursor, 0, file, line, mtr); - err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG - | BTR_KEEP_SYS_FLAG - | BTR_NO_UNDO_LOG_FLAG, - &cursor, tuple, &rec, - &dummy_big_rec, 0, NULL, mtr); - ut_a(err == DB_SUCCESS); + ut_ad(cursor.flag == BTR_CUR_BINARY); + + err = btr_cur_optimistic_insert( + BTR_NO_LOCKING_FLAG | BTR_KEEP_SYS_FLAG + | BTR_NO_UNDO_LOG_FLAG, &cursor, tuple, &rec, + &dummy_big_rec, 0, NULL, mtr); + + if (err == DB_FAIL) { + err = btr_cur_pessimistic_insert( + BTR_NO_LOCKING_FLAG | BTR_KEEP_SYS_FLAG + | BTR_NO_UNDO_LOG_FLAG, + &cursor, tuple, &rec, &dummy_big_rec, 0, NULL, mtr); + ut_a(err == DB_SUCCESS); + } } /**************************************************************//** diff --git a/storage/xtradb/btr/btr0cur.c b/storage/xtradb/btr/btr0cur.c index 26db7329b7e..61c07ac792e 100644 --- a/storage/xtradb/btr/btr0cur.c +++ b/storage/xtradb/btr/btr0cur.c @@ -1412,7 +1412,12 @@ fail_err: if (UNIV_UNLIKELY(reorg)) { ut_a(zip_size); - ut_a(*rec); + /* It's possible for rec to be NULL if the + page is compressed. This is because a + reorganized page may become incompressible. */ + if (!*rec) { + goto fail; + } } } @@ -1548,20 +1553,9 @@ btr_cur_pessimistic_insert( ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, btr_cur_get_block(cursor), MTR_MEMO_PAGE_X_FIX)); - /* Try first an optimistic insert; reset the cursor flag: we do not - assume anything of how it was positioned */ - cursor->flag = BTR_CUR_BINARY; - err = btr_cur_optimistic_insert(flags, cursor, entry, rec, - big_rec, n_ext, thr, mtr); - if (err != DB_FAIL) { - - return(err); - } - - /* Retry with a pessimistic insert. Check locks and write to undo log, - if specified */ + /* Check locks and write to undo log, if specified */ err = btr_cur_ins_lock_and_undo(flags, cursor, entry, thr, mtr, &dummy_inh); @@ -2188,8 +2182,12 @@ any_extern: goto err_exit; } - max_size = old_rec_size - + page_get_max_insert_size_after_reorganize(page, 1); + /* We do not attempt to reorganize if the page is compressed. + This is because the page may fail to compress after reorganization. */ + max_size = page_zip + ? page_get_max_insert_size(page, 1) + : (old_rec_size + + page_get_max_insert_size_after_reorganize(page, 1)); if (!(((max_size >= BTR_CUR_PAGE_REORGANIZE_LIMIT) && (max_size >= new_rec_size)) @@ -2559,7 +2557,12 @@ make_external: err = DB_SUCCESS; goto return_after_reservations; } else { - ut_a(optim_err != DB_UNDERFLOW); + /* If the page is compressed and it initially + compresses very well, and there is a subsequent insert + of a badly-compressing record, it is possible for + btr_cur_optimistic_update() to return DB_UNDERFLOW and + btr_cur_insert_if_possible() to return FALSE. */ + ut_a(page_zip || optim_err != DB_UNDERFLOW); /* Out of space: reset the free bits. */ if (!dict_index_is_clust(index) @@ -2588,7 +2591,9 @@ make_external: was_first = page_cur_is_before_first(page_cursor); /* Lock checks and undo logging were already performed by - btr_cur_upd_lock_and_undo(). */ + btr_cur_upd_lock_and_undo(). We do not try + btr_cur_optimistic_insert() because + btr_cur_insert_if_possible() already failed above. */ err = btr_cur_pessimistic_insert(BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG diff --git a/storage/xtradb/btr/btr0pcur.c b/storage/xtradb/btr/btr0pcur.c index 0de7b63f92d..b335e2c8aee 100644 --- a/storage/xtradb/btr/btr0pcur.c +++ b/storage/xtradb/btr/btr0pcur.c @@ -354,44 +354,39 @@ btr_pcur_restore_position_func( /* Restore the old search mode */ cursor->search_mode = old_mode; - if (btr_pcur_is_on_user_rec(cursor)) { - switch (cursor->rel_pos) { - case BTR_PCUR_ON: - if (!cmp_dtuple_rec( - tuple, btr_pcur_get_rec(cursor), - rec_get_offsets(btr_pcur_get_rec(cursor), - index, NULL, - ULINT_UNDEFINED, &heap))) { + switch (cursor->rel_pos) { + case BTR_PCUR_ON: + if (btr_pcur_is_on_user_rec(cursor) + && !cmp_dtuple_rec( + tuple, btr_pcur_get_rec(cursor), + rec_get_offsets(btr_pcur_get_rec(cursor), + index, NULL, + ULINT_UNDEFINED, &heap))) { - /* We have to store the NEW value for - the modify clock, since the cursor can - now be on a different page! But we can - retain the value of old_rec */ + /* We have to store the NEW value for + the modify clock, since the cursor can + now be on a different page! But we can + retain the value of old_rec */ - cursor->block_when_stored = - btr_pcur_get_block(cursor); - cursor->modify_clock = - buf_block_get_modify_clock( - cursor->block_when_stored); - cursor->old_stored = BTR_PCUR_OLD_STORED; + cursor->block_when_stored = + btr_pcur_get_block(cursor); + cursor->modify_clock = + buf_block_get_modify_clock( + cursor->block_when_stored); + cursor->old_stored = BTR_PCUR_OLD_STORED; - mem_heap_free(heap); + mem_heap_free(heap); - return(TRUE); - } - - break; - case BTR_PCUR_BEFORE: - page_cur_move_to_next(btr_pcur_get_page_cur(cursor)); - break; - case BTR_PCUR_AFTER: - page_cur_move_to_prev(btr_pcur_get_page_cur(cursor)); - break; -#ifdef UNIV_DEBUG - default: - ut_error; -#endif /* UNIV_DEBUG */ + return(TRUE); } +#ifdef UNIV_DEBUG + /* fall through */ + case BTR_PCUR_BEFORE: + case BTR_PCUR_AFTER: + break; + default: + ut_error; +#endif /* UNIV_DEBUG */ } mem_heap_free(heap); diff --git a/storage/xtradb/buf/buf0buf.c b/storage/xtradb/buf/buf0buf.c index 6ce77372dac..bbc1042ca78 100644 --- a/storage/xtradb/buf/buf0buf.c +++ b/storage/xtradb/buf/buf0buf.c @@ -336,15 +336,6 @@ be effective only if PFS_GROUP_BUFFER_SYNC is defined. */ # endif /* !PFS_SKIP_BUFFER_MUTEX_RWLOCK */ #endif /* UNIV_PFS_MUTEX || UNIV_PFS_RWLOCK */ -/** A chunk of buffers. The buffer pool is allocated in chunks. (moved to buf0buf.h)*/ -//struct buf_chunk_struct{ -// ulint mem_size; /*!< allocated size of the chunk */ -// ulint size; /*!< size of frames[] and blocks[] */ -// void* mem; /*!< pointer to the memory area which -// was allocated for the frames */ -// buf_block_t* blocks; /*!< array of buffer control blocks */ -//}; - /********************************************************************//** Gets the smallest oldest_modification lsn for any page in the pool. Returns zero if all modified pages have been flushed to disk. @@ -1028,7 +1019,8 @@ buf_chunk_init( /*===========*/ buf_pool_t* buf_pool, /*!< in: buffer pool instance */ buf_chunk_t* chunk, /*!< out: chunk of buffers */ - ulint mem_size) /*!< in: requested size in bytes */ + ulint mem_size, /*!< in: requested size in bytes */ + ibool populate) /*!< in: virtual page preallocation */ { buf_block_t* block; byte* frame; @@ -1044,7 +1036,7 @@ buf_chunk_init( + (UNIV_PAGE_SIZE - 1), UNIV_PAGE_SIZE); chunk->mem_size = mem_size; - chunk->mem = os_mem_alloc_large(&chunk->mem_size); + chunk->mem = os_mem_alloc_large(&chunk->mem_size, populate); if (UNIV_UNLIKELY(chunk->mem == NULL)) { @@ -1254,6 +1246,7 @@ buf_pool_init_instance( /*===================*/ buf_pool_t* buf_pool, /*!< in: buffer pool instance */ ulint buf_pool_size, /*!< in: size in bytes */ + ibool populate, /*!< in: virtual page preallocation */ ulint instance_no) /*!< in: id of the instance */ { ulint i; @@ -1286,7 +1279,7 @@ buf_pool_init_instance( UT_LIST_INIT(buf_pool->free); - if (!buf_chunk_init(buf_pool, chunk, buf_pool_size)) { + if (!buf_chunk_init(buf_pool, chunk, buf_pool_size, populate)) { mem_free(chunk); mem_free(buf_pool); @@ -1381,6 +1374,7 @@ ulint buf_pool_init( /*==========*/ ulint total_size, /*!< in: size of the total pool in bytes */ + ibool populate, /*!< in: virtual page preallocation */ ulint n_instances) /*!< in: number of instances */ { ulint i; @@ -1398,7 +1392,7 @@ buf_pool_init( for (i = 0; i < n_instances; i++) { buf_pool_t* ptr = &buf_pool_ptr[i]; - if (buf_pool_init_instance(ptr, size, i) != DB_SUCCESS) { + if (buf_pool_init_instance(ptr, size, populate, i) != DB_SUCCESS) { /* Free all the instances created so far. */ buf_pool_free(i); @@ -4973,7 +4967,7 @@ buf_stats_aggregate_pool_info( Collect buffer pool stats information for a buffer pool. Also record aggregated stats if there are more than one buffer pool in the server */ -static +UNIV_INTERN void buf_stats_get_pool_info( /*====================*/ diff --git a/storage/xtradb/buf/buf0lru.c b/storage/xtradb/buf/buf0lru.c index e8300107f3d..a6a1f8dcf9c 100644 --- a/storage/xtradb/buf/buf0lru.c +++ b/storage/xtradb/buf/buf0lru.c @@ -2384,7 +2384,7 @@ buf_LRU_free_one_page( #endif mutex_t* block_mutex = buf_page_get_mutex(bpage); - ut_ad(buf_pool_mutex_own(buf_pool)); + ut_ad(mutex_own(&buf_pool->LRU_list_mutex)); ut_ad(mutex_own(block_mutex)); if (buf_LRU_block_remove_hashed_page(bpage, TRUE) diff --git a/storage/xtradb/buf/buf0rea.c b/storage/xtradb/buf/buf0rea.c index c29dcbf0444..67379d614a0 100644 --- a/storage/xtradb/buf/buf0rea.c +++ b/storage/xtradb/buf/buf0rea.c @@ -64,7 +64,7 @@ buf_read_page_handle_error( == BUF_BLOCK_FILE_PAGE); /* First unfix and release lock on the bpage */ - buf_pool_mutex_enter(buf_pool); + mutex_enter(&buf_pool->LRU_list_mutex); mutex_enter(buf_page_get_mutex(bpage)); ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ); ut_ad(bpage->buf_fix_count == 0); @@ -85,7 +85,7 @@ buf_read_page_handle_error( buf_pool->n_pend_reads--; mutex_exit(buf_page_get_mutex(bpage)); - buf_pool_mutex_exit(buf_pool); + mutex_exit(&buf_pool->LRU_list_mutex); } /********************************************************************//** diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 32ec2d9d858..5cf3b021510 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -874,7 +874,7 @@ extern "C" UNIV_INTERN ibool thd_is_replication_slave_thread( /*============================*/ - void* thd) /*!< in: thread handle (THD*) */ + const void* thd) /*!< in: thread handle (THD*) */ { return((ibool) thd_slave_thread((THD*) thd)); } @@ -2465,6 +2465,122 @@ ha_innobase::init_table_handle_for_HANDLER(void) reset_template(); } +#ifdef HAVE_REPLICATION +/* The last read master log coordinates in the slave info file */ +static char master_log_fname[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN] = ""; +static int master_log_pos; +/* The slave relay log coordinates in the slave info file after startup */ +static char original_relay_log_fname[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN] = ""; +static int original_relay_log_pos; +/* The master log coordinates in the slave info file after startup */ +static char original_master_log_fname[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN] = ""; +static int original_master_log_pos; +#endif + +/*****************************************************************//** +Overwrites the MySQL relay log info file with the current master and relay log +coordinates from InnoDB. Skips overwrite if the master log position did not +change from the last overwrite. If the InnoDB master log position is equal +to position that was read from the info file on startup before any overwrites, +restores the original positions. */ +static +void +innobase_do_overwrite_relay_log_info(void) +/*======================================*/ +{ +#ifdef HAVE_REPLICATION + char info_fname[FN_REFLEN]; + File info_fd = -1; + int error = 0; + char buff[FN_REFLEN*2+22*2+4]; + char *relay_info_log_pos; + size_t buf_len; + + if (master_log_fname[0] == '\0') { + fprintf(stderr, + "InnoDB: something wrong with relay-log.info. " + "InnoDB will not overwrite it.\n"); + return; + } + + if (strcmp(master_log_fname, trx_sys_mysql_master_log_name) == 0 + && master_log_pos == trx_sys_mysql_master_log_pos) { + fprintf(stderr, + "InnoDB: InnoDB and relay-log.info are synchronized. " + "InnoDB will not overwrite it.\n"); + return; + } + + /* If we overwrite the file back to the original master log position, + restore the original relay log position too. This is required because + we might have rolled back a prepared transaction and restored the + original master log position from the InnoDB trx sys header, but the + corresponding relay log position points to an already-purged file. */ + if (strcmp(original_master_log_fname, trx_sys_mysql_master_log_name) + == 0 + && (original_master_log_pos == trx_sys_mysql_master_log_pos)) { + + strncpy(trx_sys_mysql_relay_log_name, original_relay_log_fname, + TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); + trx_sys_mysql_relay_log_pos = original_relay_log_pos; + } + + fn_format(info_fname, relay_log_info_file, mysql_data_home, "", + MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH); + + if (access(info_fname, F_OK)) { + /* File does not exist */ + error = 1; + goto skip_overwrite; + } + + /* File exists */ + info_fd = my_open(info_fname, O_RDWR|O_BINARY, MYF(MY_WME)); + if (info_fd < 0) { + error = 1; + goto skip_overwrite; + } + + relay_info_log_pos = strmov(buff, trx_sys_mysql_relay_log_name); + *relay_info_log_pos ++= '\n'; + relay_info_log_pos = longlong2str(trx_sys_mysql_relay_log_pos, + relay_info_log_pos, 10); + *relay_info_log_pos ++= '\n'; + relay_info_log_pos = strmov(relay_info_log_pos, + trx_sys_mysql_master_log_name); + *relay_info_log_pos ++= '\n'; + relay_info_log_pos = longlong2str(trx_sys_mysql_master_log_pos, + relay_info_log_pos, 10); + *relay_info_log_pos = '\n'; + + buf_len = (relay_info_log_pos - buff) + 1; + if (my_write(info_fd, (uchar *)buff, buf_len, MY_WME) != buf_len) { + error = 1; + } else if (my_sync(info_fd, MY_WME)) { + error = 1; + } + + if (info_fd >= 0) { + my_close(info_fd, MYF(0)); + } + + strncpy(master_log_fname, trx_sys_mysql_relay_log_name, + TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); + master_log_pos = trx_sys_mysql_master_log_pos; + +skip_overwrite: + if (error) { + fprintf(stderr, + "InnoDB: ERROR: error occured during overwriting " + "relay-log.info.\n"); + } else { + fprintf(stderr, + "InnoDB: relay-log.info was overwritten.\n"); + } +#endif +} + + /*********************************************************************//** Opens an InnoDB database. @return 0 on success, error code on failure */ @@ -2598,12 +2714,13 @@ innobase_init( #ifdef HAVE_REPLICATION #ifdef MYSQL_SERVER /* read master log position from relay-log.info if exists */ - char fname[FN_REFLEN+128]; - int pos; + char info_fname[FN_REFLEN]; + char relay_log_fname[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN]; + int relay_log_pos; int info_fd; IO_CACHE info_file; - fname[0] = '\0'; + info_fname[0] = '\0'; if(innobase_overwrite_relay_log_info) { @@ -2612,13 +2729,14 @@ innobase_init( " Updates by other storage engines may not be synchronized.\n"); bzero((char*) &info_file, sizeof(info_file)); - fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32); + fn_format(info_fname, relay_log_info_file, mysql_data_home, "", 4+32); int error=0; - if (!access(fname,F_OK)) { + if (!access(info_fname,F_OK)) { /* exist */ - if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0) { + if ((info_fd = my_open(info_fname, O_RDWR | O_BINARY, + MYF(MY_WME))) < 0) { error=1; } else if (init_io_cache(&info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME))) { @@ -2629,16 +2747,18 @@ innobase_init( relay_info_error: if (info_fd >= 0) my_close(info_fd, MYF(0)); - fname[0] = '\0'; + master_log_fname[0] = '\0'; goto skip_relay; } } else { - fname[0] = '\0'; + master_log_fname[0] = '\0'; goto skip_relay; } - if (init_strvar_from_file(fname, sizeof(fname), &info_file, "") || /* dummy (it is relay-log) */ - init_intvar_from_file(&pos, &info_file, BIN_LOG_HEADER_SIZE)) { + if (init_strvar_from_file(relay_log_fname, sizeof(relay_log_fname), + &info_file, "") + || /* dummy (it is relay-log) */ init_intvar_from_file( + &relay_log_pos, &info_file, BIN_LOG_HEADER_SIZE)) { end_io_cache(&info_file); error=1; goto relay_info_error; @@ -2647,13 +2767,19 @@ relay_info_error: fprintf(stderr, "InnoDB: relay-log.info is detected.\n" "InnoDB: relay log: position %u, file name %s\n", - pos, fname); + relay_log_pos, relay_log_fname); - strncpy(trx_sys_mysql_relay_log_name, fname, TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); - trx_sys_mysql_relay_log_pos = (ib_int64_t) pos; + strncpy(trx_sys_mysql_relay_log_name, relay_log_fname, + TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); + trx_sys_mysql_relay_log_pos = (ib_int64_t) relay_log_pos; - if (init_strvar_from_file(fname, sizeof(fname), &info_file, "") || - init_intvar_from_file(&pos, &info_file, 0)) { + strncpy(original_relay_log_fname, relay_log_fname, + TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); + original_relay_log_pos = relay_log_pos; + + if (init_strvar_from_file(master_log_fname, sizeof(master_log_fname), + &info_file, "") + || init_intvar_from_file(&master_log_pos, &info_file, 0)) { end_io_cache(&info_file); error=1; goto relay_info_error; @@ -2661,10 +2787,15 @@ relay_info_error: fprintf(stderr, "InnoDB: master log: position %u, file name %s\n", - pos, fname); + master_log_pos, master_log_fname); - strncpy(trx_sys_mysql_master_log_name, fname, TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); - trx_sys_mysql_master_log_pos = (ib_int64_t) pos; + strncpy(trx_sys_mysql_master_log_name, master_log_fname, + TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); + trx_sys_mysql_master_log_pos = (ib_int64_t) master_log_pos; + + strncpy(original_master_log_fname, master_log_fname, + TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); + original_master_log_pos = master_log_pos; end_io_cache(&info_file); if (info_fd >= 0) @@ -2999,75 +3130,9 @@ innobase_change_buffering_inited_ok: goto mem_free_and_error; } -#ifdef HAVE_REPLICATION -#ifdef MYSQL_SERVER if(innobase_overwrite_relay_log_info) { - /* If InnoDB progressed from relay-log.info, overwrite it */ - if (fname[0] == '\0') { - fprintf(stderr, - "InnoDB: Something is wrong with the file relay-info.log. InnoDB will not overwrite it.\n"); - } else if (0 != strcmp(fname, trx_sys_mysql_master_log_name) - || pos != trx_sys_mysql_master_log_pos) { - /* Overwrite relay-log.info */ - bzero((char*) &info_file, sizeof(info_file)); - fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32); - - int error = 0; - - if (!access(fname,F_OK)) { - /* exist */ - if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0) { - error = 1; - } else if (init_io_cache(&info_file, info_fd, IO_SIZE*2, - WRITE_CACHE, 0L, 0, MYF(MY_WME))) { - error = 1; - } - - if (error) { - if (info_fd >= 0) - my_close(info_fd, MYF(0)); - goto skip_overwrite; - } - } else { - error = 1; - goto skip_overwrite; - } - - char buff[FN_REFLEN*2+22*2+4], *pos; - - my_b_seek(&info_file, 0L); - pos=strmov(buff, trx_sys_mysql_relay_log_name); - *pos++='\n'; - pos=longlong10_to_str(trx_sys_mysql_relay_log_pos, pos, 10); - *pos++='\n'; - pos=strmov(pos, trx_sys_mysql_master_log_name); - *pos++='\n'; - pos=longlong10_to_str(trx_sys_mysql_master_log_pos, pos, 10); - *pos='\n'; - - if (my_b_write(&info_file, (uchar*) buff, (size_t) (pos-buff)+1)) - error = 1; - if (flush_io_cache(&info_file)) - error = 1; - - end_io_cache(&info_file); - if (info_fd >= 0) - my_close(info_fd, MYF(0)); -skip_overwrite: - if (error) { - fprintf(stderr, - "InnoDB: ERROR: An error occurred while overwriting relay-log.info.\n"); - } else { - fprintf(stderr, - "InnoDB: The file relay-log.info was successfully overwritten.\n"); - } - } else { - fprintf(stderr, - "InnoDB: InnoDB and relay-log.info are synchronized. InnoDB will not overwrite it.\n"); + innobase_do_overwrite_relay_log_info(); } - } -#endif /* MYSQL_SERVER */ -#endif /* HAVE_REPLICATION */ innobase_old_blocks_pct = buf_LRU_old_ratio_update( innobase_old_blocks_pct, TRUE); @@ -3170,6 +3235,32 @@ innobase_alter_table_flags( | HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE); } +/****************************************************************//** +Copy the current replication position from MySQL to a transaction. */ +static +void +innobase_copy_repl_coords_to_trx( +/*=============================*/ + const THD* thd, /*!< in: thread handle */ + trx_t* trx) /*!< in/out: transaction */ +{ + if (thd && thd_is_replication_slave_thread(thd)) { + /* Update the replication position info inside InnoDB. + In embedded server, does nothing. */ + const char *log_file_name, *group_relay_log_name; + ulonglong log_pos, relay_log_pos; + bool res = rpl_get_position_info(&log_file_name, &log_pos, + &group_relay_log_name, + &relay_log_pos); + if (res) { + trx->mysql_master_log_file_name = log_file_name; + trx->mysql_master_log_pos = (ib_int64_t)log_pos; + trx->mysql_relay_log_file_name = group_relay_log_name; + trx->mysql_relay_log_pos = (ib_int64_t)relay_log_pos; + } + } +} + /*****************************************************************//** Commits a transaction in an InnoDB database. */ static @@ -3179,27 +3270,12 @@ innobase_commit_low( trx_t* trx) /*!< in: transaction handle */ { if (trx_is_started(trx)) { -#ifdef HAVE_REPLICATION -#ifdef MYSQL_SERVER - THD *thd=current_thd; - if (thd && thd_is_replication_slave_thread(thd)) { - /* Update the replication position info inside InnoDB. - In embedded server, does nothing. */ - const char *log_file_name, *group_relay_log_name; - ulonglong log_pos, relay_log_pos; - bool res = rpl_get_position_info(&log_file_name, &log_pos, - &group_relay_log_name, - &relay_log_pos); - if (res) { - trx->mysql_master_log_file_name = log_file_name; - trx->mysql_master_log_pos = (ib_int64_t)log_pos; - trx->mysql_relay_log_file_name = group_relay_log_name; - trx->mysql_relay_log_pos = (ib_int64_t)relay_log_pos; - } - } -#endif /* MYSQL_SERVER */ -#endif /* HAVE_REPLICATION */ + /* Save the current replication position for write to trx sys + header for undo purposes, see the comment at corresponding call + at innobase_xa_prepare(). */ + + innobase_copy_repl_coords_to_trx(current_thd, trx); trx_commit_for_mysql(trx); } @@ -3399,6 +3475,9 @@ innobase_commit( if (all || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { + DBUG_EXECUTE_IF("crash_innodb_before_commit", + DBUG_SUICIDE();); + /* Run the fast part of commit if we did not already. */ if (!trx_is_active_commit_ordered(trx)) { innobase_commit_ordered_2(trx, thd); @@ -11559,7 +11638,27 @@ innobase_xa_prepare( ut_ad(trx_is_registered_for_2pc(trx)); + /* Update the replication position info in current trx. This + is different from the binlog position update that happens + during XA COMMIT. In contrast to that, the slave position is + an actual part of the changes made by this transaction and thus + must be updated in the XA PREPARE stage. Since the trx sys + header page changes are not undo-logged, again store this + position in a different field in the XA COMMIT stage, so that + it might be used in case of rollbacks. */ + + /* Since currently there might be only one slave SQL thread, we + don't need to take any precautions (e.g. prepare_commit_mutex) + to ensure position ordering. Revisit this in 5.6 which has + both the multi-threaded replication to cause us problems and + the group commit to solve them. */ + + innobase_copy_repl_coords_to_trx(thd, trx); + error = (int) trx_prepare_for_mysql(trx); + + DBUG_EXECUTE_IF("crash_innodb_after_prepare", + DBUG_SUICIDE();); } else { /* We just mark the SQL statement ended and do not do a transaction prepare */ @@ -11652,6 +11751,22 @@ innobase_rollback_by_xid( if (trx) { int ret = innobase_rollback_trx(trx); trx_free_for_background(trx); + + if (innobase_overwrite_relay_log_info) { + + /* On rollback of a prepared transaction revert the + current slave positions to the ones recorded by the + last COMMITTed transaction. This has an effect of + undoing the position change caused by the transaction + being rolled back. Assumes single-threaded slave SQL + thread. If the server has non-master write traffic + with XA rollbacks, this will cause additional spurious + slave info log overwrites, which should be harmless. */ + + trx_sys_print_committed_mysql_master_log_pos(); + innobase_do_overwrite_relay_log_info(); + } + return(ret); } else { return(XAER_NOTA); @@ -12670,6 +12785,12 @@ static MYSQL_SYSVAR_LONGLONG(buffer_pool_size, innobase_buffer_pool_size, "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.", NULL, NULL, 128*1024*1024L, 5*1024*1024L, LONGLONG_MAX, 1024*1024L); +static MYSQL_SYSVAR_BOOL(buffer_pool_populate, srv_buf_pool_populate, + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, + "Preallocate (pre-fault) the page frames required for the mapping " + "established by the buffer pool memory region. Disabled by default.", + NULL, NULL, FALSE); + static MYSQL_SYSVAR_LONG(buffer_pool_instances, innobase_buffer_pool_instances, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Number of buffer pool instances, set to higher value on high-end machines to increase scalability", @@ -13049,6 +13170,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(additional_mem_pool_size), MYSQL_SYSVAR(autoextend_increment), MYSQL_SYSVAR(buffer_pool_size), + MYSQL_SYSVAR(buffer_pool_populate), MYSQL_SYSVAR(buffer_pool_instances), MYSQL_SYSVAR(buffer_pool_shm_key), MYSQL_SYSVAR(buffer_pool_shm_checksum), @@ -13194,7 +13316,10 @@ i_s_innodb_buffer_pool_pages, i_s_innodb_buffer_pool_pages_index, i_s_innodb_buffer_pool_pages_blob, i_s_innodb_admin_command, -i_s_innodb_changed_pages +i_s_innodb_changed_pages, +i_s_innodb_buffer_page, +i_s_innodb_buffer_page_lru, +i_s_innodb_buffer_stats maria_declare_plugin_end; /** @brief Initialize the default value of innodb_commit_concurrency. diff --git a/storage/xtradb/handler/i_s.cc b/storage/xtradb/handler/i_s.cc index 57a091ea80d..29a80594344 100644 --- a/storage/xtradb/handler/i_s.cc +++ b/storage/xtradb/handler/i_s.cc @@ -64,8 +64,93 @@ extern "C" { #include "buf0lru.h" /* for XTRA_LRU_[DUMP/RESTORE] */ #include "btr0btr.h" /* for btr_page_get_index_id */ #include "log0online.h" +#include "btr0btr.h" +#include "page0zip.h" +#include "log0log.h" } +/** structure associates a name string with a file page type and/or buffer +page state. */ +struct buffer_page_desc_str_struct{ + const char* type_str; /*!< String explain the page + type/state */ + ulint type_value; /*!< Page type or page state */ +}; + +typedef struct buffer_page_desc_str_struct buf_page_desc_str_t; + +/** Any states greater than FIL_PAGE_TYPE_LAST would be treated as unknown. */ +#define I_S_PAGE_TYPE_UNKNOWN (FIL_PAGE_TYPE_LAST + 1) + +/** We also define I_S_PAGE_TYPE_INDEX as the Index Page's position +in i_s_page_type[] array */ +#define I_S_PAGE_TYPE_INDEX 1 + +/** Name string for File Page Types */ +static buf_page_desc_str_t i_s_page_type[] = { + {"ALLOCATED", FIL_PAGE_TYPE_ALLOCATED}, + {"INDEX", FIL_PAGE_INDEX}, + {"UNDO_LOG", FIL_PAGE_UNDO_LOG}, + {"INODE", FIL_PAGE_INODE}, + {"IBUF_FREE_LIST", FIL_PAGE_IBUF_FREE_LIST}, + {"IBUF_BITMAP", FIL_PAGE_IBUF_BITMAP}, + {"SYSTEM", FIL_PAGE_TYPE_SYS}, + {"TRX_SYSTEM", FIL_PAGE_TYPE_TRX_SYS}, + {"FILE_SPACE_HEADER", FIL_PAGE_TYPE_FSP_HDR}, + {"EXTENT_DESCRIPTOR", FIL_PAGE_TYPE_XDES}, + {"BLOB", FIL_PAGE_TYPE_BLOB}, + {"COMPRESSED_BLOB", FIL_PAGE_TYPE_ZBLOB}, + {"COMPRESSED_BLOB2", FIL_PAGE_TYPE_ZBLOB2}, + {"UNKNOWN", I_S_PAGE_TYPE_UNKNOWN} +}; + +/* Check if we can hold all page type in a 4 bit value */ +#if I_S_PAGE_TYPE_UNKNOWN > 1<<4 +# error "i_s_page_type[] is too large" +#endif + +/** This structure defines information we will fetch from pages +currently cached in the buffer pool. It will be used to populate +table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE */ +struct buffer_page_info_struct{ + ulint block_id; /*!< Buffer Pool block ID */ + unsigned space_id:32; /*!< Tablespace ID */ + unsigned page_num:32; /*!< Page number/offset */ + unsigned access_time:32; /*!< Time of first access */ + unsigned pool_id:MAX_BUFFER_POOLS_BITS; + /*!< Buffer Pool ID. Must be less than + MAX_BUFFER_POOLS */ + unsigned flush_type:2; /*!< Flush type */ + unsigned io_fix:2; /*!< type of pending I/O operation */ + unsigned fix_count:19; /*!< Count of how manyfold this block + is bufferfixed */ + unsigned hashed:1; /*!< Whether hash index has been + built on this page */ + unsigned is_old:1; /*!< TRUE if the block is in the old + blocks in buf_pool->LRU_old */ + unsigned freed_page_clock:31; /*!< the value of + buf_pool->freed_page_clock */ + unsigned zip_ssize:PAGE_ZIP_SSIZE_BITS; + /*!< Compressed page size */ + unsigned page_state:BUF_PAGE_STATE_BITS; /*!< Page state */ + unsigned page_type:4; /*!< Page type */ + unsigned num_recs; + /*!< Number of records on Page */ + unsigned data_size; + /*!< Sum of the sizes of the records */ + lsn_t newest_mod; /*!< Log sequence number of + the youngest modification */ + lsn_t oldest_mod; /*!< Log sequence number of + the oldest modification */ + index_id_t index_id; /*!< Index ID if a index page */ +}; + +typedef struct buffer_page_info_struct buf_page_info_t; + +/** maximum number of buffer page info we would cache. */ +#define MAX_BUF_INFO_CACHED 10000 + + #define OK(expr) \ if ((expr) != 0) { \ DBUG_RETURN(1); \ @@ -1570,7 +1655,6 @@ i_s_cmpmem_fill_low( buf_pool = buf_pool_from_array(i); - //buf_pool_mutex_enter(buf_pool); mutex_enter(&buf_pool->zip_free_mutex); for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) { @@ -1601,7 +1685,6 @@ i_s_cmpmem_fill_low( } } - //buf_pool_mutex_exit(buf_pool); mutex_exit(&buf_pool->zip_free_mutex); if (status) { @@ -1771,6 +1854,1755 @@ UNIV_INTERN struct st_maria_plugin i_s_innodb_cmpmem_reset = INNODB_VERSION_STR, MariaDB_PLUGIN_MATURITY_STABLE }; +/* Fields of the dynamic table INNODB_BUFFER_POOL_STATS. */ +static ST_FIELD_INFO i_s_innodb_buffer_stats_fields_info[] = +{ +#define IDX_BUF_STATS_POOL_ID 0 + {STRUCT_FLD(field_name, "POOL_ID"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_POOL_SIZE 1 + {STRUCT_FLD(field_name, "POOL_SIZE"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_FREE_BUFFERS 2 + {STRUCT_FLD(field_name, "FREE_BUFFERS"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_LRU_LEN 3 + {STRUCT_FLD(field_name, "DATABASE_PAGES"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_OLD_LRU_LEN 4 + {STRUCT_FLD(field_name, "OLD_DATABASE_PAGES"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_FLUSH_LIST_LEN 5 + {STRUCT_FLD(field_name, "MODIFIED_DATABASE_PAGES"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_PENDING_ZIP 6 + {STRUCT_FLD(field_name, "PENDING_DECOMPRESS"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_PENDING_READ 7 + {STRUCT_FLD(field_name, "PENDING_READS"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_FLUSH_LRU 8 + {STRUCT_FLD(field_name, "PENDING_FLUSH_LRU"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_FLUSH_LIST 9 + {STRUCT_FLD(field_name, "PENDING_FLUSH_LIST"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_PAGE_YOUNG 10 + {STRUCT_FLD(field_name, "PAGES_MADE_YOUNG"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_PAGE_NOT_YOUNG 11 + {STRUCT_FLD(field_name, "PAGES_NOT_MADE_YOUNG"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_PAGE_YOUNG_RATE 12 + {STRUCT_FLD(field_name, "PAGES_MADE_YOUNG_RATE"), + STRUCT_FLD(field_length, MAX_FLOAT_STR_LENGTH), + STRUCT_FLD(field_type, MYSQL_TYPE_FLOAT), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_PAGE_NOT_YOUNG_RATE 13 + {STRUCT_FLD(field_name, "PAGES_MADE_NOT_YOUNG_RATE"), + STRUCT_FLD(field_length, MAX_FLOAT_STR_LENGTH), + STRUCT_FLD(field_type, MYSQL_TYPE_FLOAT), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_PAGE_READ 14 + {STRUCT_FLD(field_name, "NUMBER_PAGES_READ"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_PAGE_CREATED 15 + {STRUCT_FLD(field_name, "NUMBER_PAGES_CREATED"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_PAGE_WRITTEN 16 + {STRUCT_FLD(field_name, "NUMBER_PAGES_WRITTEN"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_PAGE_READ_RATE 17 + {STRUCT_FLD(field_name, "PAGES_READ_RATE"), + STRUCT_FLD(field_length, MAX_FLOAT_STR_LENGTH), + STRUCT_FLD(field_type, MYSQL_TYPE_FLOAT), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_PAGE_CREATE_RATE 18 + {STRUCT_FLD(field_name, "PAGES_CREATE_RATE"), + STRUCT_FLD(field_length, MAX_FLOAT_STR_LENGTH), + STRUCT_FLD(field_type, MYSQL_TYPE_FLOAT), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_PAGE_WRITTEN_RATE 19 + {STRUCT_FLD(field_name, "PAGES_WRITTEN_RATE"), + STRUCT_FLD(field_length, MAX_FLOAT_STR_LENGTH), + STRUCT_FLD(field_type, MYSQL_TYPE_FLOAT), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_GET 20 + {STRUCT_FLD(field_name, "NUMBER_PAGES_GET"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_HIT_RATE 21 + {STRUCT_FLD(field_name, "HIT_RATE"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_MADE_YOUNG_PCT 22 + {STRUCT_FLD(field_name, "YOUNG_MAKE_PER_THOUSAND_GETS"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_NOT_MADE_YOUNG_PCT 23 + {STRUCT_FLD(field_name, "NOT_YOUNG_MAKE_PER_THOUSAND_GETS"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_READ_AHREAD 24 + {STRUCT_FLD(field_name, "NUMBER_PAGES_READ_AHEAD"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_READ_AHEAD_EVICTED 25 + {STRUCT_FLD(field_name, "NUMBER_READ_AHEAD_EVICTED"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_READ_AHEAD_RATE 26 + {STRUCT_FLD(field_name, "READ_AHEAD_RATE"), + STRUCT_FLD(field_length, MAX_FLOAT_STR_LENGTH), + STRUCT_FLD(field_type, MYSQL_TYPE_FLOAT), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_READ_AHEAD_EVICT_RATE 27 + {STRUCT_FLD(field_name, "READ_AHEAD_EVICTED_RATE"), + STRUCT_FLD(field_length, MAX_FLOAT_STR_LENGTH), + STRUCT_FLD(field_type, MYSQL_TYPE_FLOAT), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_LRU_IO_SUM 28 + {STRUCT_FLD(field_name, "LRU_IO_TOTAL"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_LRU_IO_CUR 29 + {STRUCT_FLD(field_name, "LRU_IO_CURRENT"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_UNZIP_SUM 30 + {STRUCT_FLD(field_name, "UNCOMPRESS_TOTAL"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_STATS_UNZIP_CUR 31 + {STRUCT_FLD(field_name, "UNCOMPRESS_CURRENT"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + + END_OF_ST_FIELD_INFO +}; + +/*******************************************************************//** +Fill Information Schema table INNODB_BUFFER_POOL_STATS for a particular +buffer pool +@return 0 on success, 1 on failure */ +static +int +i_s_innodb_stats_fill( +/*==================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + const buf_pool_info_t* info) /*!< in: buffer pool + information */ +{ + TABLE* table; + Field** fields; + + DBUG_ENTER("i_s_innodb_stats_fill"); + + table = tables->table; + + fields = table->field; + + OK(fields[IDX_BUF_STATS_POOL_ID]->store(info->pool_unique_id)); + + OK(fields[IDX_BUF_STATS_POOL_SIZE]->store(info->pool_size)); + + OK(fields[IDX_BUF_STATS_LRU_LEN]->store(info->lru_len)); + + OK(fields[IDX_BUF_STATS_OLD_LRU_LEN]->store(info->old_lru_len)); + + OK(fields[IDX_BUF_STATS_FREE_BUFFERS]->store(info->free_list_len)); + + OK(fields[IDX_BUF_STATS_FLUSH_LIST_LEN]->store( + info->flush_list_len)); + + OK(fields[IDX_BUF_STATS_PENDING_ZIP]->store(info->n_pend_unzip)); + + OK(fields[IDX_BUF_STATS_PENDING_READ]->store(info->n_pend_reads)); + + OK(fields[IDX_BUF_STATS_FLUSH_LRU]->store(info->n_pending_flush_lru)); + + OK(fields[IDX_BUF_STATS_FLUSH_LIST]->store(info->n_pending_flush_list)); + + OK(fields[IDX_BUF_STATS_PAGE_YOUNG]->store(info->n_pages_made_young)); + + OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG]->store( + info->n_pages_not_made_young)); + + OK(fields[IDX_BUF_STATS_PAGE_YOUNG_RATE]->store( + info->page_made_young_rate)); + + OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG_RATE]->store( + info->page_not_made_young_rate)); + + OK(fields[IDX_BUF_STATS_PAGE_READ]->store(info->n_pages_read)); + + OK(fields[IDX_BUF_STATS_PAGE_CREATED]->store(info->n_pages_created)); + + OK(fields[IDX_BUF_STATS_PAGE_WRITTEN]->store(info->n_pages_written)); + + OK(fields[IDX_BUF_STATS_GET]->store(info->n_page_gets)); + + OK(fields[IDX_BUF_STATS_PAGE_READ_RATE]->store(info->pages_read_rate)); + + OK(fields[IDX_BUF_STATS_PAGE_CREATE_RATE]->store(info->pages_created_rate)); + + OK(fields[IDX_BUF_STATS_PAGE_WRITTEN_RATE]->store(info->pages_written_rate)); + + if (info->n_page_get_delta) { + OK(fields[IDX_BUF_STATS_HIT_RATE]->store( + 1000 - (1000 * info->page_read_delta + / info->n_page_get_delta))); + + OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store( + 1000 * info->young_making_delta + / info->n_page_get_delta)); + + OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store( + 1000 * info->not_young_making_delta + / info->n_page_get_delta)); + } else { + OK(fields[IDX_BUF_STATS_HIT_RATE]->store(0)); + OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(0)); + OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(0)); + } + + OK(fields[IDX_BUF_STATS_READ_AHREAD]->store(info->n_ra_pages_read)); + + OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICTED]->store( + info->n_ra_pages_evicted)); + + OK(fields[IDX_BUF_STATS_READ_AHEAD_RATE]->store( + info->pages_readahead_rate)); + + OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICT_RATE]->store( + info->pages_evicted_rate)); + + OK(fields[IDX_BUF_STATS_LRU_IO_SUM]->store(info->io_sum)); + + OK(fields[IDX_BUF_STATS_LRU_IO_CUR]->store(info->io_cur)); + + OK(fields[IDX_BUF_STATS_UNZIP_SUM]->store(info->unzip_sum)); + + OK(fields[IDX_BUF_STATS_UNZIP_CUR]->store( info->unzip_cur)); + + DBUG_RETURN(schema_table_store_record(thd, table)); +} + +/*******************************************************************//** +This is the function that loops through each buffer pool and fetch buffer +pool stats to information schema table: I_S_INNODB_BUFFER_POOL_STATS +@return 0 on success, 1 on failure */ +static +int +i_s_innodb_buffer_stats_fill_table( +/*===============================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + Item* ) /*!< in: condition (ignored) */ +{ + int status = 0; + buf_pool_info_t* pool_info; + + DBUG_ENTER("i_s_innodb_buffer_fill_general"); + + /* Only allow the PROCESS privilege holder to access the stats */ + if (check_global_access(thd, PROCESS_ACL)) { + DBUG_RETURN(0); + } + + pool_info = (buf_pool_info_t*) mem_zalloc( + srv_buf_pool_instances * sizeof *pool_info); + + /* Walk through each buffer pool */ + for (ulint i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + + /* Fetch individual buffer pool info */ + buf_stats_get_pool_info(buf_pool, i, pool_info); + + status = i_s_innodb_stats_fill(thd, tables, &pool_info[i]); + + /* If something goes wrong, break and return */ + if (status) { + break; + } + } + + mem_free(pool_info); + + DBUG_RETURN(status); +} + +/*******************************************************************//** +Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STATS. +@return 0 on success, 1 on failure */ +static +int +i_s_innodb_buffer_pool_stats_init( +/*==============================*/ + void* p) /*!< in/out: table schema object */ +{ + ST_SCHEMA_TABLE* schema; + + DBUG_ENTER("i_s_innodb_buffer_pool_stats_init"); + + schema = reinterpret_cast(p); + + schema->fields_info = i_s_innodb_buffer_stats_fields_info; + schema->fill_table = i_s_innodb_buffer_stats_fill_table; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_maria_plugin i_s_innodb_buffer_stats = +{ + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &i_s_info), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "INNODB_BUFFER_POOL_STATS"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, plugin_author), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "InnoDB Buffer Pool Statistics Information "), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, i_s_innodb_buffer_pool_stats_init), + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ + STRUCT_FLD(deinit, i_s_common_deinit), + + /* plugin version (for SHOW PLUGINS) */ + /* unsigned int */ + STRUCT_FLD(version, INNODB_VERSION_SHORT), + + /* struct st_mysql_show_var* */ + STRUCT_FLD(status_vars, NULL), + + /* struct st_mysql_sys_var** */ + STRUCT_FLD(system_vars, NULL), + + INNODB_VERSION_STR, MariaDB_PLUGIN_MATURITY_STABLE +}; + +/* Fields of the dynamic table INNODB_BUFFER_POOL_PAGE. */ +static ST_FIELD_INFO i_s_innodb_buffer_page_fields_info[] = +{ +#define IDX_BUFFER_POOL_ID 0 + {STRUCT_FLD(field_name, "POOL_ID"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_BLOCK_ID 1 + {STRUCT_FLD(field_name, "BLOCK_ID"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_SPACE 2 + {STRUCT_FLD(field_name, "SPACE"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_NUM 3 + {STRUCT_FLD(field_name, "PAGE_NUMBER"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_TYPE 4 + {STRUCT_FLD(field_name, "PAGE_TYPE"), + STRUCT_FLD(field_length, 64), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_FLUSH_TYPE 5 + {STRUCT_FLD(field_name, "FLUSH_TYPE"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_FIX_COUNT 6 + {STRUCT_FLD(field_name, "FIX_COUNT"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_HASHED 7 + {STRUCT_FLD(field_name, "IS_HASHED"), + STRUCT_FLD(field_length, 3), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_NEWEST_MOD 8 + {STRUCT_FLD(field_name, "NEWEST_MODIFICATION"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_OLDEST_MOD 9 + {STRUCT_FLD(field_name, "OLDEST_MODIFICATION"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_ACCESS_TIME 10 + {STRUCT_FLD(field_name, "ACCESS_TIME"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_TABLE_NAME 11 + {STRUCT_FLD(field_name, "TABLE_NAME"), + STRUCT_FLD(field_length, 1024), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_INDEX_NAME 12 + {STRUCT_FLD(field_name, "INDEX_NAME"), + STRUCT_FLD(field_length, 1024), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_NUM_RECS 13 + {STRUCT_FLD(field_name, "NUMBER_RECORDS"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_DATA_SIZE 14 + {STRUCT_FLD(field_name, "DATA_SIZE"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_ZIP_SIZE 15 + {STRUCT_FLD(field_name, "COMPRESSED_SIZE"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_STATE 16 + {STRUCT_FLD(field_name, "PAGE_STATE"), + STRUCT_FLD(field_length, 64), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_IO_FIX 17 + {STRUCT_FLD(field_name, "IO_FIX"), + STRUCT_FLD(field_length, 64), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_IS_OLD 18 + {STRUCT_FLD(field_name, "IS_OLD"), + STRUCT_FLD(field_length, 3), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUFFER_PAGE_FREE_CLOCK 19 + {STRUCT_FLD(field_name, "FREE_PAGE_CLOCK"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + + END_OF_ST_FIELD_INFO +}; + +/*******************************************************************//** +Fill Information Schema table INNODB_BUFFER_PAGE with information +cached in the buf_page_info_t array +@return 0 on success, 1 on failure */ +static +int +i_s_innodb_buffer_page_fill( +/*========================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + const buf_page_info_t* info_array, /*!< in: array cached page + info */ + ulint num_page, /*!< in: number of page info + cached */ + mem_heap_t* heap) /*!< in: temp heap memory */ +{ + TABLE* table; + Field** fields; + + DBUG_ENTER("i_s_innodb_buffer_page_fill"); + + table = tables->table; + + fields = table->field; + + /* Iterate through the cached array and fill the I_S table rows */ + for (ulint i = 0; i < num_page; i++) { + const buf_page_info_t* page_info; + const char* table_name; + const char* index_name; + const char* state_str; + enum buf_page_state state; + + page_info = info_array + i; + + table_name = NULL; + index_name = NULL; + state_str = NULL; + + OK(fields[IDX_BUFFER_POOL_ID]->store(page_info->pool_id)); + + OK(fields[IDX_BUFFER_BLOCK_ID]->store(page_info->block_id)); + + OK(fields[IDX_BUFFER_PAGE_SPACE]->store(page_info->space_id)); + + OK(fields[IDX_BUFFER_PAGE_NUM]->store(page_info->page_num)); + + OK(field_store_string( + fields[IDX_BUFFER_PAGE_TYPE], + i_s_page_type[page_info->page_type].type_str)); + + OK(fields[IDX_BUFFER_PAGE_FLUSH_TYPE]->store( + page_info->flush_type)); + + OK(fields[IDX_BUFFER_PAGE_FIX_COUNT]->store( + page_info->fix_count)); + + if (page_info->hashed) { + OK(field_store_string( + fields[IDX_BUFFER_PAGE_HASHED], "YES")); + } else { + OK(field_store_string( + fields[IDX_BUFFER_PAGE_HASHED], "NO")); + } + + OK(fields[IDX_BUFFER_PAGE_NEWEST_MOD]->store( + (longlong) page_info->newest_mod, true)); + + OK(fields[IDX_BUFFER_PAGE_OLDEST_MOD]->store( + (longlong) page_info->oldest_mod, true)); + + OK(fields[IDX_BUFFER_PAGE_ACCESS_TIME]->store( + page_info->access_time)); + + /* If this is an index page, fetch the index name + and table name */ + if (page_info->page_type == I_S_PAGE_TYPE_INDEX) { + const dict_index_t* index; + + mutex_enter(&dict_sys->mutex); + index = dict_index_get_if_in_cache_low( + page_info->index_id); + + /* Copy the index/table name under mutex. We + do not want to hold the InnoDB mutex while + filling the IS table */ + if (index) { + const char* name_ptr = index->name; + + if (name_ptr[0] == TEMP_INDEX_PREFIX) { + name_ptr++; + } + + index_name = mem_heap_strdup(heap, name_ptr); + + table_name = mem_heap_strdup(heap, + index->table_name); + + } + + mutex_exit(&dict_sys->mutex); + } + + OK(field_store_string( + fields[IDX_BUFFER_PAGE_TABLE_NAME], table_name)); + + OK(field_store_string( + fields[IDX_BUFFER_PAGE_INDEX_NAME], index_name)); + + OK(fields[IDX_BUFFER_PAGE_NUM_RECS]->store( + page_info->num_recs)); + + OK(fields[IDX_BUFFER_PAGE_DATA_SIZE]->store( + page_info->data_size)); + + OK(fields[IDX_BUFFER_PAGE_ZIP_SIZE]->store( + page_info->zip_ssize + ? (PAGE_ZIP_MIN_SIZE >> 1) << page_info->zip_ssize + : 0)); + +#if BUF_PAGE_STATE_BITS > 3 +# error "BUF_PAGE_STATE_BITS > 3, please ensure that all 1<(page_info->page_state); + + switch (state) { + /* First three states are for compression pages and + are not states we would get as we scan pages through + buffer blocks */ + case BUF_BLOCK_ZIP_FREE: + case BUF_BLOCK_ZIP_PAGE: + case BUF_BLOCK_ZIP_DIRTY: + state_str = NULL; + break; + case BUF_BLOCK_NOT_USED: + state_str = "NOT_USED"; + break; + case BUF_BLOCK_READY_FOR_USE: + state_str = "READY_FOR_USE"; + break; + case BUF_BLOCK_FILE_PAGE: + state_str = "FILE_PAGE"; + break; + case BUF_BLOCK_MEMORY: + state_str = "MEMORY"; + break; + case BUF_BLOCK_REMOVE_HASH: + state_str = "REMOVE_HASH"; + break; + }; + + OK(field_store_string(fields[IDX_BUFFER_PAGE_STATE], + state_str)); + + switch (page_info->io_fix) { + case BUF_IO_NONE: + OK(field_store_string(fields[IDX_BUFFER_PAGE_IO_FIX], + "IO_NONE")); + break; + case BUF_IO_READ: + OK(field_store_string(fields[IDX_BUFFER_PAGE_IO_FIX], + "IO_READ")); + break; + case BUF_IO_WRITE: + OK(field_store_string(fields[IDX_BUFFER_PAGE_IO_FIX], + "IO_WRITE")); + break; + case BUF_IO_PIN: + OK(field_store_string(fields[IDX_BUFFER_PAGE_IO_FIX], + "IO_PIN")); + break; + } + + OK(field_store_string(fields[IDX_BUFFER_PAGE_IS_OLD], + (page_info->is_old) ? "YES" : "NO")); + + OK(fields[IDX_BUFFER_PAGE_FREE_CLOCK]->store( + page_info->freed_page_clock)); + + if (schema_table_store_record(thd, table)) { + DBUG_RETURN(1); + } + } + + DBUG_RETURN(0); +} + +/*******************************************************************//** +Set appropriate page type to a buf_page_info_t structure */ +static +void +i_s_innodb_set_page_type( +/*=====================*/ + buf_page_info_t*page_info, /*!< in/out: structure to fill with + scanned info */ + ulint page_type, /*!< in: page type */ + const byte* frame) /*!< in: buffer frame */ +{ + if (page_type == FIL_PAGE_INDEX) { + const page_t* page = (const page_t*) frame; + + /* FIL_PAGE_INDEX is a bit special, its value + is defined as 17855, so we cannot use FIL_PAGE_INDEX + to index into i_s_page_type[] array, its array index + in the i_s_page_type[] array is I_S_PAGE_TYPE_INDEX + (1) */ + page_info->page_type = I_S_PAGE_TYPE_INDEX; + + page_info->index_id = btr_page_get_index_id(page); + + page_info->data_size = (ulint)(page_header_get_field( + page, PAGE_HEAP_TOP) - (page_is_comp(page) + ? PAGE_NEW_SUPREMUM_END + : PAGE_OLD_SUPREMUM_END) + - page_header_get_field(page, PAGE_GARBAGE)); + + page_info->num_recs = page_get_n_recs(page); + } else if (page_type >= I_S_PAGE_TYPE_UNKNOWN) { + /* Encountered an unknown page type */ + page_info->page_type = I_S_PAGE_TYPE_UNKNOWN; + } else { + /* Make sure we get the right index into the + i_s_page_type[] array */ + ut_a(page_type == i_s_page_type[page_type].type_value); + + page_info->page_type = page_type; + } + + if (page_info->page_type == FIL_PAGE_TYPE_ZBLOB + || page_info->page_type == FIL_PAGE_TYPE_ZBLOB2) { + page_info->page_num = mach_read_from_4( + frame + FIL_PAGE_OFFSET); + page_info->space_id = mach_read_from_4( + frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + } +} +/*******************************************************************//** +Scans pages in the buffer cache, and collect their general information +into the buf_page_info_t array which is zero-filled. So any fields +that are not initialized in the function will default to 0 */ +static +void +i_s_innodb_buffer_page_get_info( +/*============================*/ + const buf_page_t*bpage, /*!< in: buffer pool page to scan */ + ulint pool_id, /*!< in: buffer pool id */ + ulint pos, /*!< in: buffer block position in + buffer pool or in the LRU list */ + buf_page_info_t*page_info) /*!< in: zero filled info structure; + out: structure filled with scanned + info */ +{ + ut_ad(pool_id < MAX_BUFFER_POOLS); + + page_info->pool_id = pool_id; + + page_info->block_id = pos; + + page_info->page_state = buf_page_get_state(bpage); + + /* Only fetch information for buffers that map to a tablespace, + that is, buffer page with state BUF_BLOCK_ZIP_PAGE, + BUF_BLOCK_ZIP_DIRTY or BUF_BLOCK_FILE_PAGE */ + if (buf_page_in_file(bpage)) { + const byte* frame; + ulint page_type; + + page_info->space_id = buf_page_get_space(bpage); + + page_info->page_num = buf_page_get_page_no(bpage); + + page_info->flush_type = bpage->flush_type; + + page_info->fix_count = bpage->buf_fix_count; + + page_info->newest_mod = bpage->newest_modification; + + page_info->oldest_mod = bpage->oldest_modification; + + page_info->access_time = bpage->access_time; + + page_info->zip_ssize = bpage->zip.ssize; + + page_info->io_fix = bpage->io_fix; + + page_info->is_old = bpage->old; + + page_info->freed_page_clock = bpage->freed_page_clock; + + if (page_info->page_state == BUF_BLOCK_FILE_PAGE) { + const buf_block_t*block; + + block = reinterpret_cast(bpage); + frame = block->frame; + page_info->hashed = (block->index != NULL); + } else { + ut_ad(page_info->zip_ssize); + frame = bpage->zip.data; + } + + page_type = fil_page_get_type(frame); + + i_s_innodb_set_page_type(page_info, page_type, frame); + } else { + page_info->page_type = I_S_PAGE_TYPE_UNKNOWN; + } +} + +/*******************************************************************//** +This is the function that goes through each block of the buffer pool +and fetch information to information schema tables: INNODB_BUFFER_PAGE. +@return 0 on success, 1 on failure */ +static +int +i_s_innodb_fill_buffer_pool( +/*========================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + buf_pool_t* buf_pool, /*!< in: buffer pool to scan */ + const ulint pool_id) /*!< in: buffer pool id */ +{ + int status = 0; + mem_heap_t* heap; + + DBUG_ENTER("i_s_innodb_fill_buffer_pool"); + + heap = mem_heap_create(10000); + + /* Go through each chunk of buffer pool. Currently, we only + have one single chunk for each buffer pool */ + for (ulint n = 0; n < buf_pool->n_chunks; n++) { + const buf_block_t* block; + ulint n_blocks; + buf_page_info_t* info_buffer; + ulint num_page; + ulint mem_size; + ulint chunk_size; + ulint num_to_process = 0; + ulint block_id = 0; + mutex_t* block_mutex; + + /* Get buffer block of the nth chunk */ + block = buf_get_nth_chunk_block(buf_pool, n, &chunk_size); + num_page = 0; + + while (chunk_size > 0) { + /* we cache maximum MAX_BUF_INFO_CACHED number of + buffer page info */ + num_to_process = ut_min(chunk_size, + MAX_BUF_INFO_CACHED); + + mem_size = num_to_process * sizeof(buf_page_info_t); + + /* For each chunk, we'll pre-allocate information + structures to cache the page information read from + the buffer pool. Doing so before obtain any mutex */ + info_buffer = (buf_page_info_t*) mem_heap_zalloc( + heap, mem_size); + + /* GO through each block in the chunk */ + for (n_blocks = num_to_process; n_blocks--; block++) { + block_mutex = buf_page_get_mutex_enter(&block->page); + i_s_innodb_buffer_page_get_info( + &block->page, pool_id, block_id, + info_buffer + num_page); + mutex_exit(block_mutex); + block_id++; + num_page++; + } + + + /* Fill in information schema table with information + just collected from the buffer chunk scan */ + status = i_s_innodb_buffer_page_fill( + thd, tables, info_buffer, + num_page, heap); + + /* If something goes wrong, break and return */ + if (status) { + break; + } + + mem_heap_empty(heap); + chunk_size -= num_to_process; + num_page = 0; + } + } + + mem_heap_free(heap); + + DBUG_RETURN(status); +} + +/*******************************************************************//** +Fill page information for pages in InnoDB buffer pool to the +dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE +@return 0 on success, 1 on failure */ +static +int +i_s_innodb_buffer_page_fill_table( +/*==============================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + Item* ) /*!< in: condition (ignored) */ +{ + int status = 0; + + DBUG_ENTER("i_s_innodb_buffer_page_fill_table"); + + /* deny access to user without PROCESS privilege */ + if (check_global_access(thd, PROCESS_ACL)) { + DBUG_RETURN(0); + } + + /* Walk through each buffer pool */ + for (ulint i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + + /* Fetch information from pages in this buffer pool, + and fill the corresponding I_S table */ + status = i_s_innodb_fill_buffer_pool(thd, tables, buf_pool, i); + + /* If something wrong, break and return */ + if (status) { + break; + } + } + + DBUG_RETURN(status); +} + +/*******************************************************************//** +Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE. +@return 0 on success, 1 on failure */ +static +int +i_s_innodb_buffer_page_init( +/*========================*/ + void* p) /*!< in/out: table schema object */ +{ + ST_SCHEMA_TABLE* schema; + + DBUG_ENTER("i_s_innodb_buffer_page_init"); + + schema = reinterpret_cast(p); + + schema->fields_info = i_s_innodb_buffer_page_fields_info; + schema->fill_table = i_s_innodb_buffer_page_fill_table; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_maria_plugin i_s_innodb_buffer_page = +{ + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &i_s_info), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "INNODB_BUFFER_PAGE"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, plugin_author), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "InnoDB Buffer Page Information"), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, i_s_innodb_buffer_page_init), + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ + STRUCT_FLD(deinit, i_s_common_deinit), + + /* plugin version (for SHOW PLUGINS) */ + /* unsigned int */ + STRUCT_FLD(version, INNODB_VERSION_SHORT), + + /* struct st_mysql_show_var* */ + STRUCT_FLD(status_vars, NULL), + + /* struct st_mysql_sys_var** */ + STRUCT_FLD(system_vars, NULL), + + INNODB_VERSION_STR, MariaDB_PLUGIN_MATURITY_STABLE +}; + +static ST_FIELD_INFO i_s_innodb_buf_page_lru_fields_info[] = +{ +#define IDX_BUF_LRU_POOL_ID 0 + {STRUCT_FLD(field_name, "POOL_ID"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_POS 1 + {STRUCT_FLD(field_name, "LRU_POSITION"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_SPACE 2 + {STRUCT_FLD(field_name, "SPACE"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_NUM 3 + {STRUCT_FLD(field_name, "PAGE_NUMBER"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_TYPE 4 + {STRUCT_FLD(field_name, "PAGE_TYPE"), + STRUCT_FLD(field_length, 64), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_FLUSH_TYPE 5 + {STRUCT_FLD(field_name, "FLUSH_TYPE"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_FIX_COUNT 6 + {STRUCT_FLD(field_name, "FIX_COUNT"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_HASHED 7 + {STRUCT_FLD(field_name, "IS_HASHED"), + STRUCT_FLD(field_length, 3), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_NEWEST_MOD 8 + {STRUCT_FLD(field_name, "NEWEST_MODIFICATION"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_OLDEST_MOD 9 + {STRUCT_FLD(field_name, "OLDEST_MODIFICATION"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_ACCESS_TIME 10 + {STRUCT_FLD(field_name, "ACCESS_TIME"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_TABLE_NAME 11 + {STRUCT_FLD(field_name, "TABLE_NAME"), + STRUCT_FLD(field_length, 1024), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_INDEX_NAME 12 + {STRUCT_FLD(field_name, "INDEX_NAME"), + STRUCT_FLD(field_length, 1024), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_NUM_RECS 13 + {STRUCT_FLD(field_name, "NUMBER_RECORDS"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_DATA_SIZE 14 + {STRUCT_FLD(field_name, "DATA_SIZE"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_ZIP_SIZE 15 + {STRUCT_FLD(field_name, "COMPRESSED_SIZE"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_STATE 16 + {STRUCT_FLD(field_name, "COMPRESSED"), + STRUCT_FLD(field_length, 3), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_IO_FIX 17 + {STRUCT_FLD(field_name, "IO_FIX"), + STRUCT_FLD(field_length, 64), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_IS_OLD 18 + {STRUCT_FLD(field_name, "IS_OLD"), + STRUCT_FLD(field_length, 3), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_BUF_LRU_PAGE_FREE_CLOCK 19 + {STRUCT_FLD(field_name, "FREE_PAGE_CLOCK"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + + END_OF_ST_FIELD_INFO +}; + +/*******************************************************************//** +Fill Information Schema table INNODB_BUFFER_PAGE_LRU with information +cached in the buf_page_info_t array +@return 0 on success, 1 on failure */ +static +int +i_s_innodb_buf_page_lru_fill( +/*=========================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + const buf_page_info_t* info_array, /*!< in: array cached page + info */ + ulint num_page) /*!< in: number of page info + cached */ +{ + TABLE* table; + Field** fields; + mem_heap_t* heap; + + DBUG_ENTER("i_s_innodb_buf_page_lru_fill"); + + table = tables->table; + + fields = table->field; + + heap = mem_heap_create(1000); + + /* Iterate through the cached array and fill the I_S table rows */ + for (ulint i = 0; i < num_page; i++) { + const buf_page_info_t* page_info; + const char* table_name; + const char* index_name; + const char* state_str; + enum buf_page_state state; + + table_name = NULL; + index_name = NULL; + state_str = NULL; + + page_info = info_array + i; + + OK(fields[IDX_BUF_LRU_POOL_ID]->store(page_info->pool_id)); + + OK(fields[IDX_BUF_LRU_POS]->store(page_info->block_id)); + + OK(fields[IDX_BUF_LRU_PAGE_SPACE]->store(page_info->space_id)); + + OK(fields[IDX_BUF_LRU_PAGE_NUM]->store(page_info->page_num)); + + OK(field_store_string( + fields[IDX_BUF_LRU_PAGE_TYPE], + i_s_page_type[page_info->page_type].type_str)); + + OK(fields[IDX_BUF_LRU_PAGE_FLUSH_TYPE]->store( + page_info->flush_type)); + + OK(fields[IDX_BUF_LRU_PAGE_FIX_COUNT]->store( + page_info->fix_count)); + + if (page_info->hashed) { + OK(field_store_string( + fields[IDX_BUF_LRU_PAGE_HASHED], "YES")); + } else { + OK(field_store_string( + fields[IDX_BUF_LRU_PAGE_HASHED], "NO")); + } + + OK(fields[IDX_BUF_LRU_PAGE_NEWEST_MOD]->store( + page_info->newest_mod, true)); + + OK(fields[IDX_BUF_LRU_PAGE_OLDEST_MOD]->store( + page_info->oldest_mod, true)); + + OK(fields[IDX_BUF_LRU_PAGE_ACCESS_TIME]->store( + page_info->access_time)); + + /* If this is an index page, fetch the index name + and table name */ + if (page_info->page_type == I_S_PAGE_TYPE_INDEX) { + const dict_index_t* index; + + mutex_enter(&dict_sys->mutex); + index = dict_index_get_if_in_cache_low( + page_info->index_id); + + /* Copy the index/table name under mutex. We + do not want to hold the InnoDB mutex while + filling the IS table */ + if (index) { + const char* name_ptr = index->name; + + if (name_ptr[0] == TEMP_INDEX_PREFIX) { + name_ptr++; + } + + index_name = mem_heap_strdup(heap, name_ptr); + + table_name = mem_heap_strdup(heap, + index->table_name); + } + + mutex_exit(&dict_sys->mutex); + } + + OK(field_store_string( + fields[IDX_BUF_LRU_PAGE_TABLE_NAME], table_name)); + + OK(field_store_string( + fields[IDX_BUF_LRU_PAGE_INDEX_NAME], index_name)); + OK(fields[IDX_BUF_LRU_PAGE_NUM_RECS]->store( + page_info->num_recs)); + + OK(fields[IDX_BUF_LRU_PAGE_DATA_SIZE]->store( + page_info->data_size)); + + OK(fields[IDX_BUF_LRU_PAGE_ZIP_SIZE]->store( + page_info->zip_ssize ? + 512 << page_info->zip_ssize : 0)); + + state = static_cast(page_info->page_state); + + switch (state) { + /* Compressed page */ + case BUF_BLOCK_ZIP_PAGE: + case BUF_BLOCK_ZIP_DIRTY: + state_str = "YES"; + break; + /* Uncompressed page */ + case BUF_BLOCK_FILE_PAGE: + state_str = "NO"; + break; + /* We should not see following states */ + case BUF_BLOCK_ZIP_FREE: + case BUF_BLOCK_READY_FOR_USE: + case BUF_BLOCK_NOT_USED: + case BUF_BLOCK_MEMORY: + case BUF_BLOCK_REMOVE_HASH: + state_str = NULL; + break; + }; + + OK(field_store_string(fields[IDX_BUF_LRU_PAGE_STATE], + state_str)); + + switch (page_info->io_fix) { + case BUF_IO_NONE: + OK(field_store_string(fields[IDX_BUF_LRU_PAGE_IO_FIX], + "IO_NONE")); + break; + case BUF_IO_READ: + OK(field_store_string(fields[IDX_BUF_LRU_PAGE_IO_FIX], + "IO_READ")); + break; + case BUF_IO_WRITE: + OK(field_store_string(fields[IDX_BUF_LRU_PAGE_IO_FIX], + "IO_WRITE")); + break; + } + + OK(field_store_string(fields[IDX_BUF_LRU_PAGE_IS_OLD], + (page_info->is_old) ? "YES" : "NO")); + + OK(fields[IDX_BUF_LRU_PAGE_FREE_CLOCK]->store( + page_info->freed_page_clock)); + + if (schema_table_store_record(thd, table)) { + mem_heap_free(heap); + DBUG_RETURN(1); + } + + mem_heap_empty(heap); + } + + mem_heap_free(heap); + + DBUG_RETURN(0); +} + +/*******************************************************************//** +This is the function that goes through buffer pool's LRU list +and fetch information to INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU. +@return 0 on success, 1 on failure */ +static +int +i_s_innodb_fill_buffer_lru( +/*=======================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + buf_pool_t* buf_pool, /*!< in: buffer pool to scan */ + const ulint pool_id) /*!< in: buffer pool id */ +{ + int status = 0; + buf_page_info_t* info_buffer; + ulint lru_pos = 0; + const buf_page_t* bpage; + ulint lru_len; + mutex_t* block_mutex; + + DBUG_ENTER("i_s_innodb_fill_buffer_lru"); + + RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name); + + /* Obtain buf_pool mutex before allocate info_buffer, since + UT_LIST_GET_LEN(buf_pool->LRU) could change */ + mutex_enter(&buf_pool->LRU_list_mutex); + + lru_len = UT_LIST_GET_LEN(buf_pool->LRU); + + /* Print error message if malloc fail */ + info_buffer = (buf_page_info_t*) my_malloc( + lru_len * sizeof *info_buffer, MYF(MY_WME)); + + if (!info_buffer) { + status = 1; + goto exit; + } + + memset(info_buffer, 0, lru_len * sizeof *info_buffer); + + /* Walk through Pool's LRU list and print the buffer page + information */ + bpage = UT_LIST_GET_LAST(buf_pool->LRU); + + while (bpage != NULL) { + block_mutex = buf_page_get_mutex_enter(bpage); + /* Use the same function that collect buffer info for + INNODB_BUFFER_PAGE to get buffer page info */ + i_s_innodb_buffer_page_get_info(bpage, pool_id, lru_pos, + (info_buffer + lru_pos)); + + bpage = UT_LIST_GET_PREV(LRU, bpage); + mutex_exit(block_mutex); + + lru_pos++; + } + + ut_ad(lru_pos == lru_len); + ut_ad(lru_pos == UT_LIST_GET_LEN(buf_pool->LRU)); + +exit: + mutex_exit(&buf_pool->LRU_list_mutex); + + if (info_buffer) { + status = i_s_innodb_buf_page_lru_fill( + thd, tables, info_buffer, lru_len); + + my_free(info_buffer); + } + + DBUG_RETURN(status); +} + +/*******************************************************************//** +Fill page information for pages in InnoDB buffer pool to the +dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU +@return 0 on success, 1 on failure */ +static +int +i_s_innodb_buf_page_lru_fill_table( +/*===============================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + Item* ) /*!< in: condition (ignored) */ +{ + int status = 0; + + DBUG_ENTER("i_s_innodb_buf_page_lru_fill_table"); + + /* deny access to any users that do not hold PROCESS_ACL */ + if (check_global_access(thd, PROCESS_ACL)) { + DBUG_RETURN(0); + } + + /* Walk through each buffer pool */ + for (ulint i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + + /* Fetch information from pages in this buffer pool's LRU list, + and fill the corresponding I_S table */ + status = i_s_innodb_fill_buffer_lru(thd, tables, buf_pool, i); + + /* If something wrong, break and return */ + if (status) { + break; + } + } + + DBUG_RETURN(status); +} + +/*******************************************************************//** +Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU. +@return 0 on success, 1 on failure */ +static +int +i_s_innodb_buffer_page_lru_init( +/*============================*/ + void* p) /*!< in/out: table schema object */ +{ + ST_SCHEMA_TABLE* schema; + + DBUG_ENTER("i_s_innodb_buffer_page_lru_init"); + + schema = reinterpret_cast(p); + + schema->fields_info = i_s_innodb_buf_page_lru_fields_info; + schema->fill_table = i_s_innodb_buf_page_lru_fill_table; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_maria_plugin i_s_innodb_buffer_page_lru = +{ + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &i_s_info), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "INNODB_BUFFER_PAGE_LRU"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, plugin_author), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "InnoDB Buffer Page in LRU"), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, i_s_innodb_buffer_page_lru_init), + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ + STRUCT_FLD(deinit, i_s_common_deinit), + + /* plugin version (for SHOW PLUGINS) */ + /* unsigned int */ + STRUCT_FLD(version, INNODB_VERSION_SHORT), + + /* struct st_mysql_show_var* */ + STRUCT_FLD(status_vars, NULL), + + /* struct st_mysql_sys_var** */ + STRUCT_FLD(system_vars, NULL), + + INNODB_VERSION_STR, MariaDB_PLUGIN_MATURITY_STABLE +}; + /*******************************************************************//** Unbind a dynamic INFORMATION_SCHEMA table. @return 0 on success */ diff --git a/storage/xtradb/handler/i_s.h b/storage/xtradb/handler/i_s.h index a8964356747..620309bebfe 100644 --- a/storage/xtradb/handler/i_s.h +++ b/storage/xtradb/handler/i_s.h @@ -52,5 +52,8 @@ extern struct st_maria_plugin i_s_innodb_buffer_pool_pages; extern struct st_maria_plugin i_s_innodb_buffer_pool_pages_index; extern struct st_maria_plugin i_s_innodb_buffer_pool_pages_blob; extern struct st_maria_plugin i_s_innodb_changed_pages; +extern struct st_maria_plugin i_s_innodb_buffer_page; +extern struct st_maria_plugin i_s_innodb_buffer_page_lru; +extern struct st_maria_plugin i_s_innodb_buffer_stats; #endif /* i_s_h */ diff --git a/storage/xtradb/ibuf/ibuf0ibuf.c b/storage/xtradb/ibuf/ibuf0ibuf.c index 562f207268a..78cb6e20176 100644 --- a/storage/xtradb/ibuf/ibuf0ibuf.c +++ b/storage/xtradb/ibuf/ibuf0ibuf.c @@ -3650,11 +3650,18 @@ bitmap_fail: root = ibuf_tree_root_get(&mtr); - err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG - | BTR_NO_UNDO_LOG_FLAG, - cursor, - ibuf_entry, &ins_rec, - &dummy_big_rec, 0, thr, &mtr); + err = btr_cur_optimistic_insert( + BTR_NO_LOCKING_FLAG | BTR_NO_UNDO_LOG_FLAG, + cursor, ibuf_entry, &ins_rec, + &dummy_big_rec, 0, thr, &mtr); + + if (err == DB_FAIL) { + err = btr_cur_pessimistic_insert( + BTR_NO_LOCKING_FLAG | BTR_NO_UNDO_LOG_FLAG, + cursor, ibuf_entry, &ins_rec, + &dummy_big_rec, 0, thr, &mtr); + } + mutex_exit(&ibuf_pessimistic_insert_mutex); ibuf_size_update(root, &mtr); mutex_exit(&ibuf_mutex); diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h index 1a4990be69f..d48c7f0212f 100644 --- a/storage/xtradb/include/buf0buf.h +++ b/storage/xtradb/include/buf0buf.h @@ -68,7 +68,10 @@ Created 11/5/1995 Heikki Tuuri position of the block. */ /* @} */ -#define MAX_BUFFER_POOLS 64 /*!< The maximum number of buffer +#define MAX_BUFFER_POOLS_BITS 6 /*!< Number of bits to representing + a buffer pool ID */ +#define MAX_BUFFER_POOLS (1 << MAX_BUFFER_POOLS_BITS) + /*!< The maximum number of buffer pools that can be defined */ #define BUF_POOL_WATCH_SIZE 1 /*!< Maximum number of concurrent @@ -233,6 +236,7 @@ ulint buf_pool_init( /*=========*/ ulint size, /*!< in: Size of the total pool in bytes */ + ibool populate, /*!< in: Force virtual page preallocation */ ulint n_instances); /*!< in: Number of instances */ /********************************************************************//** Frees the buffer pool at shutdown. This must not be invoked before @@ -778,6 +782,18 @@ void buf_print_io( /*=========*/ FILE* file); /*!< in: file where to print */ +/*******************************************************************//** +Collect buffer pool stats information for a buffer pool. Also +record aggregated stats if there are more than one buffer pool +in the server */ +UNIV_INTERN +void +buf_stats_get_pool_info( +/*====================*/ + buf_pool_t* buf_pool, /*!< in: buffer pool */ + ulint pool_id, /*!< in: buffer pool ID */ + buf_pool_info_t* all_pool_info); /*!< in/out: buffer pool info + to fill */ /*********************************************************************//** Returns the ratio in percents of modified pages in the buffer pool / database pages in the buffer pool. @@ -1364,12 +1380,25 @@ void buf_get_total_stat( /*===============*/ buf_pool_stat_t*tot_stat); /*!< out: buffer pool stats */ +/*********************************************************************//** +Get the nth chunk's buffer block in the specified buffer pool. +@return the nth chunk's buffer block. */ +UNIV_INLINE +buf_block_t* +buf_get_nth_chunk_block( +/*====================*/ + const buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint n, /*!< in: nth chunk in the buffer pool */ + ulint* chunk_size); /*!< in: chunk size */ #endif /* !UNIV_HOTBACKUP */ /** The common buffer control block structure for compressed and uncompressed frames */ +/** Number of bits used for buffer page states. */ +#define BUF_PAGE_STATE_BITS 3 + struct buf_page_struct{ /** @name General fields None of these bit-fields must be modified without holding @@ -1384,7 +1413,8 @@ struct buf_page_struct{ unsigned offset:32; /*!< page number; also protected by buf_pool->mutex. */ - unsigned state:3; /*!< state of the control block; also + 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 diff --git a/storage/xtradb/include/buf0buf.ic b/storage/xtradb/include/buf0buf.ic index 6595e86a8fe..221f86d9d62 100644 --- a/storage/xtradb/include/buf0buf.ic +++ b/storage/xtradb/include/buf0buf.ic @@ -36,6 +36,8 @@ Created 11/5/1995 Heikki Tuuri #include "buf0lru.h" #include "buf0rea.h" #include "srv0srv.h" +#include "buf0types.h" + /*********************************************************************//** Gets the current size of buffer buf_pool in bytes. @return size in bytes */ @@ -1354,4 +1356,21 @@ buf_pool_page_hash_x_unlock_all(void) rw_lock_x_unlock(&buf_pool->page_hash_latch); } } +/*********************************************************************//** +Get the nth chunk's buffer block in the specified buffer pool. +@return the nth chunk's buffer block. */ +UNIV_INLINE +buf_block_t* +buf_get_nth_chunk_block( +/*====================*/ + const buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint n, /*!< in: nth chunk in the buffer pool */ + ulint* chunk_size) /*!< in: chunk size */ +{ + const buf_chunk_t* chunk; + + chunk = buf_pool->chunks + n; + *chunk_size = chunk->size; + return(chunk->blocks); +} #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h index 19bf5960ae4..7da62e68e56 100644 --- a/storage/xtradb/include/fil0fil.h +++ b/storage/xtradb/include/fil0fil.h @@ -144,6 +144,8 @@ extern fil_addr_t fil_addr_null; #define FIL_PAGE_TYPE_BLOB 10 /*!< Uncompressed BLOB page */ #define FIL_PAGE_TYPE_ZBLOB 11 /*!< First compressed BLOB page */ #define FIL_PAGE_TYPE_ZBLOB2 12 /*!< Subsequent compressed BLOB page */ +#define FIL_PAGE_TYPE_LAST FIL_PAGE_TYPE_ZBLOB2 + /*!< Last page type */ /* @} */ /** Space types @{ */ diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h index 2907365a32a..51e331c3b5d 100644 --- a/storage/xtradb/include/ha_prototypes.h +++ b/storage/xtradb/include/ha_prototypes.h @@ -111,7 +111,7 @@ UNIV_INTERN ibool thd_is_replication_slave_thread( /*============================*/ - void* thd); /*!< in: thread handle (THD*) */ + const void* thd); /*!< in: thread handle (THD*) */ /******************************************************************//** Returns true if the transaction this thread is processing has edited diff --git a/storage/xtradb/include/log0log.h b/storage/xtradb/include/log0log.h index 96c4b81695a..9a149bcfa76 100644 --- a/storage/xtradb/include/log0log.h +++ b/storage/xtradb/include/log0log.h @@ -41,6 +41,9 @@ Created 12/9/1995 Heikki Tuuri #include "sync0rw.h" #endif /* !UNIV_HOTBACKUP */ +/* Type used for all log sequence number storage and arithmetics */ +typedef ib_uint64_t lsn_t; + /** Redo log buffer */ typedef struct log_struct log_t; /** Redo log group */ diff --git a/storage/xtradb/include/os0proc.h b/storage/xtradb/include/os0proc.h index fd46bd7db87..a78b1c2a250 100644 --- a/storage/xtradb/include/os0proc.h +++ b/storage/xtradb/include/os0proc.h @@ -58,7 +58,8 @@ UNIV_INTERN void* os_mem_alloc_large( /*===============*/ - ulint* n); /*!< in/out: number of bytes */ + ulint* n, /*!< in/out: number of bytes */ + ibool populate); /*!< in: virtual page preallocation */ /****************************************************************//** Frees large pages memory. */ UNIV_INTERN diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index b8820f1b7c9..a95eb8a1d58 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -182,6 +182,7 @@ extern my_bool srv_use_sys_malloc; extern ibool srv_use_sys_malloc; #endif /* UNIV_HOTBACKUP */ extern ulint srv_buf_pool_size; /*!< requested size in bytes */ +extern my_bool srv_buf_pool_populate; /*!< virtual page preallocation */ extern ulint srv_buf_pool_instances; /*!< requested number of buffer pool instances */ extern ulint srv_buf_pool_old_size; /*!< previously requested size */ extern ulint srv_buf_pool_curr_size; /*!< current size in bytes */ diff --git a/storage/xtradb/include/trx0sys.h b/storage/xtradb/include/trx0sys.h index c933fb405e1..cba21ae97a9 100644 --- a/storage/xtradb/include/trx0sys.h +++ b/storage/xtradb/include/trx0sys.h @@ -342,6 +342,14 @@ void trx_sys_print_mysql_binlog_offset(void); /*===================================*/ /*****************************************************************//** +Prints to stderr the MySQL master log offset info in the trx system header +COMMIT set of fields if the magic number shows it valid and stores it +in global variables. */ +UNIV_INTERN +void +trx_sys_print_committed_mysql_master_log_pos(void); +/*==============================================*/ +/*****************************************************************//** Prints to stderr the MySQL master log offset info in the trx system header if the magic number shows it valid. */ UNIV_INTERN @@ -534,10 +542,16 @@ We must remember this limit in order to keep file compatibility. */ //# error "UNIV_PAGE_SIZE < 4096" //#endif /** The offset of the MySQL replication info in the trx system header; -this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */ +this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below. These are +written at prepare time and are the main copy. */ #define TRX_SYS_MYSQL_MASTER_LOG_INFO (UNIV_PAGE_SIZE - 2000) #define TRX_SYS_MYSQL_RELAY_LOG_INFO (UNIV_PAGE_SIZE - 1500) +/** The copy of the above which is made at transaction COMMIT time. If binlog +crash recovery rollbacks a PREPAREd transaction, they are copied back. */ +#define TRX_SYS_COMMIT_MASTER_LOG_INFO (UNIV_PAGE_SIZE - 3000) +#define TRX_SYS_COMMIT_RELAY_LOG_INFO (UNIV_PAGE_SIZE - 2500) + /** The offset of the MySQL binlog offset info in the trx system header */ #define TRX_SYS_MYSQL_LOG_INFO (UNIV_PAGE_SIZE - 1000) #define TRX_SYS_MYSQL_LOG_MAGIC_N_FLD 0 /*!< magic number which is diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i index 9aee2a0c7f9..5d2cd2d0313 100644 --- a/storage/xtradb/include/univ.i +++ b/storage/xtradb/include/univ.i @@ -54,7 +54,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_BUGFIX 8 #ifndef PERCONA_INNODB_VERSION -#define PERCONA_INNODB_VERSION 29.0 +#define PERCONA_INNODB_VERSION 29.1 #endif /* The following is the InnoDB version as shown in diff --git a/storage/xtradb/os/os0proc.c b/storage/xtradb/os/os0proc.c index 68321e1aaf9..c9ee707e923 100644 --- a/storage/xtradb/os/os0proc.c +++ b/storage/xtradb/os/os0proc.c @@ -32,6 +32,12 @@ Created 9/30/1995 Heikki Tuuri #include "ut0mem.h" #include "ut0byte.h" +/* Linux release version */ +#if defined(UNIV_LINUX) && defined(_GNU_SOURCE) +#include /* strverscmp() */ +#include /* uname() */ +#endif + /* FreeBSD for example has only MAP_ANON, Linux has MAP_ANONYMOUS and MAP_ANON but MAP_ANON is marked as deprecated */ #if defined(MAP_ANONYMOUS) @@ -40,6 +46,13 @@ MAP_ANON but MAP_ANON is marked as deprecated */ #define OS_MAP_ANON MAP_ANON #endif +/* Linux's MAP_POPULATE */ +#if defined(MAP_POPULATE) +#define OS_MAP_POPULATE MAP_POPULATE +#else +#define OS_MAP_POPULATE 0 +#endif + UNIV_INTERN ibool os_use_large_pages; /* Large page size. This may be a boot-time option on some platforms */ UNIV_INTERN ulint os_large_page_size; @@ -62,6 +75,24 @@ os_proc_get_number(void) #endif } +/****************************************************************//** +Retrieve and compare operating system release. +@return TRUE if the OS release is equal to, or later than release. */ +UNIV_INTERN +ibool +os_compare_release( +/*===============*/ + const char* release /*!< in: OS release */ + __attribute__((unused))) +{ +#if defined(UNIV_LINUX) && defined(_GNU_SOURCE) + struct utsname name; + return uname(&name) == 0 && strverscmp(name.release, release) >= 0; +#else + return 0; +#endif +} + /****************************************************************//** Allocates large pages memory. @return allocated memory */ @@ -69,7 +100,8 @@ UNIV_INTERN void* os_mem_alloc_large( /*===============*/ - ulint* n) /*!< in/out: number of bytes */ + ulint* n, /*!< in/out: number of bytes */ + ibool populate) /*!< in: virtual page preallocation */ { void* ptr; ulint size; @@ -155,12 +187,13 @@ skip: ut_ad(ut_is_2pow(size)); size = *n = ut_2pow_round(*n + (size - 1), size); ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | OS_MAP_ANON, -1, 0); + MAP_PRIVATE | OS_MAP_ANON | + (populate ? OS_MAP_POPULATE : 0), -1, 0); if (UNIV_UNLIKELY(ptr == (void*) -1)) { fprintf(stderr, "InnoDB: mmap(%lu bytes) failed;" " errno %lu\n", (ulong) size, (ulong) errno); - ptr = NULL; + return(NULL); } else { os_fast_mutex_lock(&ut_list_mutex); ut_total_allocated_memory += size; @@ -168,6 +201,25 @@ skip: UNIV_MEM_ALLOC(ptr, size); } #endif + +#if OS_MAP_ANON && OS_MAP_POPULATE + /* MAP_POPULATE is only supported for private mappings + since Linux 2.6.23. */ + populate = populate && !os_compare_release("2.6.23"); + + if (populate) { + fprintf(stderr, "InnoDB: Warning: mmap(MAP_POPULATE) " + "is not supported for private mappings. " + "Forcing preallocation by faulting in pages.\n"); + } +#endif + + /* Initialize the entire buffer to force the allocation + of physical memory page frames. */ + if (populate) { + memset(ptr, '\0', size); + } + return(ptr); } diff --git a/storage/xtradb/page/page0page.c b/storage/xtradb/page/page0page.c index 4a389bbe5b8..e29fa2eb1e5 100644 --- a/storage/xtradb/page/page0page.c +++ b/storage/xtradb/page/page0page.c @@ -781,12 +781,18 @@ page_copy_rec_list_start( if (UNIV_LIKELY_NULL(new_page_zip)) { mtr_set_log_mode(mtr, log_mode); + DBUG_EXECUTE_IF("page_copy_rec_list_start_compress_fail", + goto zip_reorganize;); + if (UNIV_UNLIKELY (!page_zip_compress(new_page_zip, new_page, index, mtr))) { + ulint ret_pos; +#ifndef DBUG_OFF +zip_reorganize: +#endif /* DBUG_OFF */ /* Before trying to reorganize the page, store the number of preceding records on the page. */ - ulint ret_pos - = page_rec_get_n_recs_before(ret); + ret_pos = page_rec_get_n_recs_before(ret); /* Before copying, "ret" was the predecessor of the predefined supremum record. If it was the predefined infimum record, then it would @@ -807,15 +813,10 @@ page_copy_rec_list_start( btr_blob_dbg_add(new_page, index, "copy_start_reorg_fail"); return(NULL); - } else { - /* The page was reorganized: - Seek to ret_pos. */ - ret = new_page + PAGE_NEW_INFIMUM; - - do { - ret = rec_get_next_ptr(ret, TRUE); - } while (--ret_pos); } + + /* The page was reorganized: Seek to ret_pos. */ + ret = page_rec_get_nth(new_page, ret_pos); } } diff --git a/storage/xtradb/row/row0ins.c b/storage/xtradb/row/row0ins.c index b21d48c7552..3ae4c227ddc 100644 --- a/storage/xtradb/row/row0ins.c +++ b/storage/xtradb/row/row0ins.c @@ -2181,9 +2181,16 @@ row_ins_index_entry_low( goto function_exit; } - err = btr_cur_pessimistic_insert( + + err = btr_cur_optimistic_insert( 0, &cursor, entry, &insert_rec, &big_rec, n_ext, thr, &mtr); + + if (err == DB_FAIL) { + err = btr_cur_pessimistic_insert( + 0, &cursor, entry, &insert_rec, + &big_rec, n_ext, thr, &mtr); + } } } diff --git a/storage/xtradb/row/row0merge.c b/storage/xtradb/row/row0merge.c index c7d6304d6a7..0fd13f5339c 100644 --- a/storage/xtradb/row/row0merge.c +++ b/storage/xtradb/row/row0merge.c @@ -1254,11 +1254,25 @@ row_merge_read_clustered_index( goto err_exit; } + /* Store the cursor position on the last user + record on the page. */ + btr_pcur_move_to_prev_on_page(&pcur); + /* Leaf pages must never be empty, unless + this is the only page in the index tree. */ + ut_ad(btr_pcur_is_on_user_rec(&pcur) + || buf_block_get_page_no( + btr_pcur_get_block(&pcur)) + == clust_index->page); + btr_pcur_store_position(&pcur, &mtr); mtr_commit(&mtr); mtr_start(&mtr); + /* Restore position on the record, or its + predecessor if the record was purged + meanwhile. */ btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr); + /* Move to the successor of the original record. */ has_next = btr_pcur_move_to_next_user_rec(&pcur, &mtr); } @@ -2720,7 +2734,7 @@ row_merge_build_indexes( merge_files = mem_alloc(n_indexes * sizeof *merge_files); block_size = 3 * merge_sort_block_size; - block_mem = os_mem_alloc_large(&block_size); + block_mem = os_mem_alloc_large(&block_size, FALSE); for (i = 0; i < UT_ARR_SIZE(block); i++) { block[i] = (row_merge_block_t ) ((byte *) block_mem + diff --git a/storage/xtradb/srv/srv0srv.c b/storage/xtradb/srv/srv0srv.c index dff9fc07a7f..9d479ac6c87 100644 --- a/storage/xtradb/srv/srv0srv.c +++ b/storage/xtradb/srv/srv0srv.c @@ -232,6 +232,8 @@ UNIV_INTERN const byte* srv_latin1_ordering; UNIV_INTERN my_bool srv_use_sys_malloc = TRUE; /* requested size in kilobytes */ UNIV_INTERN ulint srv_buf_pool_size = ULINT_MAX; +/* force virtual page preallocation (prefault) */ +UNIV_INTERN my_bool srv_buf_pool_populate = FALSE; /* requested number of buffer pool instances */ UNIV_INTERN ulint srv_buf_pool_instances = 1; /* previously requested size */ diff --git a/storage/xtradb/srv/srv0start.c b/storage/xtradb/srv/srv0start.c index 7c98f74909e..65a775b56da 100644 --- a/storage/xtradb/srv/srv0start.c +++ b/storage/xtradb/srv/srv0start.c @@ -1543,7 +1543,8 @@ innobase_start_or_create_for_mysql(void) ((double) srv_buf_pool_size) / (1024 * 1024)); } - err = buf_pool_init(srv_buf_pool_size, srv_buf_pool_instances); + err = buf_pool_init(srv_buf_pool_size, (ibool) srv_buf_pool_populate, + srv_buf_pool_instances); ut_print_timestamp(stderr); fprintf(stderr, diff --git a/storage/xtradb/trx/trx0sys.c b/storage/xtradb/trx/trx0sys.c index 7d303c2563c..c40bf02a7a2 100644 --- a/storage/xtradb/trx/trx0sys.c +++ b/storage/xtradb/trx/trx0sys.c @@ -959,8 +959,31 @@ trx_sys_print_mysql_binlog_offset(void) } /*****************************************************************//** -Prints to stderr the MySQL master log offset info in the trx system header if -the magic number shows it valid. */ +Reads the log coordinates at the given offset in the trx sys header. */ +static +void +trx_sys_read_log_pos( +/*=================*/ + const trx_sysf_t* sys_header, /*!< in: the trx sys header */ + uint header_offset, /*!< in: coord offset in the + header */ + char* log_fn, /*!< out: the log file name */ + ib_int64_t* log_pos) /*!< out: the log poistion */ +{ + ut_memcpy(log_fn, sys_header + header_offset + TRX_SYS_MYSQL_LOG_NAME, + TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); + + *log_pos = + (((ib_int64_t)mach_read_from_4(sys_header + header_offset + + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32) + + mach_read_from_4(sys_header + header_offset + + TRX_SYS_MYSQL_LOG_OFFSET_LOW); +} + +/*****************************************************************//** +Prints to stderr the MySQL master log offset info in the trx system header +PREPARE set of fields if the magic number shows it valid and stores it +in global variables. */ UNIV_INTERN void trx_sys_print_mysql_master_log_pos(void) @@ -982,60 +1005,79 @@ trx_sys_print_mysql_master_log_pos(void) return; } + /* Copy the master log position info to global variables we can + use in ha_innobase.cc to initialize glob_mi to right values */ + trx_sys_read_log_pos(sys_header, TRX_SYS_MYSQL_MASTER_LOG_INFO, + trx_sys_mysql_master_log_name, + &trx_sys_mysql_master_log_pos); + + trx_sys_read_log_pos(sys_header, TRX_SYS_MYSQL_RELAY_LOG_INFO, + trx_sys_mysql_relay_log_name, + &trx_sys_mysql_relay_log_pos); + + mtr_commit(&mtr); + fprintf(stderr, "InnoDB: In a MySQL replication slave the last" " master binlog file\n" - "InnoDB: position %lu %lu, file name %s\n", - (ulong) mach_read_from_4(sys_header - + TRX_SYS_MYSQL_MASTER_LOG_INFO - + TRX_SYS_MYSQL_LOG_OFFSET_HIGH), - (ulong) mach_read_from_4(sys_header - + TRX_SYS_MYSQL_MASTER_LOG_INFO - + TRX_SYS_MYSQL_LOG_OFFSET_LOW), - sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO - + TRX_SYS_MYSQL_LOG_NAME); + "InnoDB: position %llu, file name %s\n", + trx_sys_mysql_master_log_pos, + trx_sys_mysql_master_log_name); fprintf(stderr, "InnoDB: and relay log file\n" - "InnoDB: position %lu %lu, file name %s\n", - (ulong) mach_read_from_4(sys_header - + TRX_SYS_MYSQL_RELAY_LOG_INFO - + TRX_SYS_MYSQL_LOG_OFFSET_HIGH), - (ulong) mach_read_from_4(sys_header - + TRX_SYS_MYSQL_RELAY_LOG_INFO - + TRX_SYS_MYSQL_LOG_OFFSET_LOW), - sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO - + TRX_SYS_MYSQL_LOG_NAME); + "InnoDB: position %llu, file name %s\n", + trx_sys_mysql_relay_log_pos, + trx_sys_mysql_relay_log_name); +} + +/*****************************************************************//** +Prints to stderr the MySQL master log offset info in the trx system header +COMMIT set of fields if the magic number shows it valid and stores it +in global variables. */ +UNIV_INTERN +void +trx_sys_print_committed_mysql_master_log_pos(void) +/*==============================================*/ +{ + trx_sysf_t* sys_header; + mtr_t mtr; + + mtr_start(&mtr); + + sys_header = trx_sysf_get(&mtr); + + if (mach_read_from_4(sys_header + TRX_SYS_COMMIT_MASTER_LOG_INFO + + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) + != TRX_SYS_MYSQL_LOG_MAGIC_N) { + + mtr_commit(&mtr); + + return; + } /* Copy the master log position info to global variables we can - use in ha_innobase.cc to initialize glob_mi to right values */ + use in ha_innobase.cc to initialize glob_mi to right values */ + trx_sys_read_log_pos(sys_header, TRX_SYS_COMMIT_MASTER_LOG_INFO, + trx_sys_mysql_master_log_name, + &trx_sys_mysql_master_log_pos); - ut_memcpy(trx_sys_mysql_master_log_name, - sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO - + TRX_SYS_MYSQL_LOG_NAME, - TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); + trx_sys_read_log_pos(sys_header, TRX_SYS_COMMIT_RELAY_LOG_INFO, + trx_sys_mysql_relay_log_name, + &trx_sys_mysql_relay_log_pos); - trx_sys_mysql_master_log_pos - = (((ib_int64_t) mach_read_from_4( - sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO - + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32) - + ((ib_int64_t) mach_read_from_4( - sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO - + TRX_SYS_MYSQL_LOG_OFFSET_LOW)); - - ut_memcpy(trx_sys_mysql_relay_log_name, - sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO - + TRX_SYS_MYSQL_LOG_NAME, - TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); - - trx_sys_mysql_relay_log_pos - = (((ib_int64_t) mach_read_from_4( - sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO - + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32) - + ((ib_int64_t) mach_read_from_4( - sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO - + TRX_SYS_MYSQL_LOG_OFFSET_LOW)); mtr_commit(&mtr); + + fprintf(stderr, + "InnoDB: In a MySQL replication slave the last" + " master binlog file\n" + "InnoDB: position %llu, file name %s\n", + trx_sys_mysql_master_log_pos, trx_sys_mysql_master_log_name); + + fprintf(stderr, + "InnoDB: and relay log file\n" + "InnoDB: position %llu, file name %s\n", + trx_sys_mysql_relay_log_pos, trx_sys_mysql_relay_log_name); } /****************************************************************//** diff --git a/storage/xtradb/trx/trx0trx.c b/storage/xtradb/trx/trx0trx.c index c9fccaad16b..eea8e861387 100644 --- a/storage/xtradb/trx/trx0trx.c +++ b/storage/xtradb/trx/trx0trx.c @@ -938,13 +938,13 @@ trx_write_serialisation_history( sys_header, trx->mysql_relay_log_file_name, trx->mysql_relay_log_pos, - TRX_SYS_MYSQL_RELAY_LOG_INFO, &mtr); + TRX_SYS_COMMIT_RELAY_LOG_INFO, &mtr); trx_sys_update_mysql_binlog_offset( sys_header, trx->mysql_master_log_file_name, trx->mysql_master_log_pos, - TRX_SYS_MYSQL_MASTER_LOG_INFO, &mtr); + TRX_SYS_COMMIT_MASTER_LOG_INFO, &mtr); trx->mysql_master_log_file_name = ""; } @@ -2050,6 +2050,23 @@ trx_prepare_off_kernel( mutex_exit(&(rseg->mutex)); + if (trx->mysql_master_log_file_name[0] != '\0') { + /* This database server is a MySQL replication slave */ + trx_sysf_t* sys_header = trx_sysf_get(&mtr); + + trx_sys_update_mysql_binlog_offset( + sys_header, + trx->mysql_relay_log_file_name, + trx->mysql_relay_log_pos, + TRX_SYS_MYSQL_RELAY_LOG_INFO, &mtr); + trx_sys_update_mysql_binlog_offset( + sys_header, + trx->mysql_master_log_file_name, + trx->mysql_master_log_pos, + TRX_SYS_MYSQL_MASTER_LOG_INFO, &mtr); + trx->mysql_master_log_file_name = ""; + } + /*--------------*/ mtr_commit(&mtr); /* This mtr commit makes the transaction prepared in the file-based diff --git a/strings/decimal.c b/strings/decimal.c index 51c4457d934..f318a234d3f 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1170,7 +1170,7 @@ int decimal2longlong(const decimal_t *from, longlong *to) And for -1234567890.1234 it would be - 7E F2 04 37 2D FB 2D + 7E F2 04 C7 2D FB 2D */ int decimal2bin(const decimal_t *from, uchar *to, int precision, int frac) { diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 95fc61f2b72..91e7da6ff32 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -18554,6 +18554,22 @@ static void test_progress_reporting() mysql_close(conn); } +/** + MDEV-3885 - connection suicide via mysql_kill() causes assertion in server +*/ + +static void test_mdev3885() +{ + int rc; + MYSQL *conn; + + myheader("test_mdev3885"); + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + rc= mysql_kill(conn, mysql_thread_id(conn)); + DIE_UNLESS(rc); + mysql_close(conn); +} + /** Bug#57058 SERVER_QUERY_WAS_SLOW not wired up. @@ -19056,6 +19072,7 @@ static struct my_tests_st my_tests[]= { { "test_bug58036", test_bug58036 }, { "test_bug57058", test_bug57058 }, { "test_bug56976", test_bug56976 }, + { "test_mdev3855", test_mdev3885 }, { "test_bug11766854", test_bug11766854 }, { "test_bug12337762", test_bug12337762 }, { "test_progress_reporting", test_progress_reporting }, diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 8da9b7dca26..5c4e2e89d10 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -78,7 +78,7 @@ ssl_error_string[] = "No error", "Unable to get certificate", "Unable to get private key", - "Private key does not match the certificate public key" + "Private key does not match the certificate public key", "SSL_CTX_set_default_verify_paths failed", "Failed to set ciphers to use", "SSL_CTX_new failed"