Browse Source

automerge

pull/73/head
Sandeep Doddaballapur 15 years ago
parent
commit
2fc1c66b1b
  1. 78
      mysql-test/include/have_dbi_dbd-mysql.inc
  2. 16
      mysql-test/include/mysqlhotcopy.inc
  3. 10
      mysql-test/mysql-test-run.pl
  4. 97
      mysql-test/std_data/checkDBI_DBD-mysql.pl
  5. 95
      mysql-test/suite/innodb/r/innodb_bug30423.result
  6. 211
      mysql-test/suite/innodb/t/innodb_bug30423.test
  7. 5
      mysql-test/suite/innodb/t/innodb_bug56143.test
  8. 95
      mysql-test/suite/innodb_plugin/r/innodb_bug30423.result
  9. 211
      mysql-test/suite/innodb_plugin/t/innodb_bug30423.test
  10. 5
      mysql-test/suite/innodb_plugin/t/innodb_bug56143.test
  11. 4
      mysql-test/suite/parts/inc/partition_check_drop.inc
  12. 13
      mysql-test/suite/parts/inc/partition_layout_check1.inc
  13. 7
      mysql-test/suite/parts/inc/partition_layout_check2.inc
  14. 2
      mysql-test/suite/parts/r/partition_recover_myisam.result
  15. 2
      mysql-test/suite/parts/t/partition_debug_sync_innodb.test
  16. 6
      mysql-test/suite/parts/t/partition_recover_myisam.test
  17. 4
      mysql-test/suite/parts/t/partition_special_innodb.test
  18. 2
      mysql-test/suite/sys_vars/r/general_log_file_basic.result
  19. 2
      mysql-test/suite/sys_vars/r/log_output_func.result
  20. 2
      mysql-test/suite/sys_vars/r/slow_query_log_file_basic.result
  21. 2
      mysql-test/suite/sys_vars/t/div_precision_increment_func.test
  22. 1
      mysql-test/suite/sys_vars/t/general_log_file_basic.test
  23. 1
      mysql-test/suite/sys_vars/t/log_output_func.test
  24. 1
      mysql-test/suite/sys_vars/t/slow_query_log_file_basic.test
  25. 2
      mysql-test/t/disabled.def
  26. 2
      sql/item.h
  27. 2
      sql/item_func.h
  28. 2
      sql/item_timefunc.h
  29. 2
      sql/sql_partition.cc
  30. 2
      sql/table.cc
  31. 156
      storage/innobase/btr/btr0cur.c
  32. 10
      storage/innobase/dict/dict0dict.c
  33. 95
      storage/innobase/handler/ha_innodb.cc
  34. 5
      storage/innobase/include/btr0cur.h
  35. 6
      storage/innobase/include/dict0mem.h
  36. 5
      storage/innobase/include/dict0types.h
  37. 4
      storage/innobase/include/rem0cmp.h
  38. 2
      storage/innobase/include/rem0cmp.ic
  39. 18
      storage/innobase/include/srv0srv.h
  40. 3
      storage/innobase/include/sync0rw.h
  41. 4
      storage/innobase/include/trx0rseg.h
  42. 5
      storage/innobase/include/trx0trx.h
  43. 14
      storage/innobase/rem/rem0cmp.c
  44. 10
      storage/innobase/row/row0vers.c
  45. 5
      storage/innobase/srv/srv0srv.c
  46. 4
      storage/innobase/sync/sync0arr.c
  47. 19
      storage/innobase/sync/sync0rw.c
  48. 26
      storage/innobase/trx/trx0trx.c
  49. 51
      storage/innodb_plugin/ChangeLog
  50. 2
      storage/innodb_plugin/btr/btr0btr.c
  51. 165
      storage/innodb_plugin/btr/btr0cur.c
  52. 2
      storage/innodb_plugin/btr/btr0sea.c
  53. 2
      storage/innodb_plugin/buf/buf0buddy.c
  54. 14
      storage/innodb_plugin/buf/buf0buf.c
  55. 44
      storage/innodb_plugin/buf/buf0lru.c
  56. 10
      storage/innodb_plugin/dict/dict0dict.c
  57. 95
      storage/innodb_plugin/handler/ha_innodb.cc
  58. 5
      storage/innodb_plugin/include/btr0cur.h
  59. 6
      storage/innodb_plugin/include/buf0buf.h
  60. 8
      storage/innodb_plugin/include/buf0buf.ic
  61. 14
      storage/innodb_plugin/include/buf0lru.h
  62. 6
      storage/innodb_plugin/include/dict0mem.h
  63. 5
      storage/innodb_plugin/include/dict0types.h
  64. 4
      storage/innodb_plugin/include/rem0cmp.h
  65. 2
      storage/innodb_plugin/include/rem0cmp.ic
  66. 18
      storage/innodb_plugin/include/srv0srv.h
  67. 3
      storage/innodb_plugin/include/sync0rw.h
  68. 4
      storage/innodb_plugin/include/trx0rseg.h
  69. 4
      storage/innodb_plugin/include/trx0trx.h
  70. 2
      storage/innodb_plugin/include/univ.i
  71. 2
      storage/innodb_plugin/mem/mem0mem.c
  72. 2
      storage/innodb_plugin/mtr/mtr0log.c
  73. 2
      storage/innodb_plugin/page/page0zip.c
  74. 14
      storage/innodb_plugin/rem/rem0cmp.c
  75. 4
      storage/innodb_plugin/row/row0upd.c
  76. 10
      storage/innodb_plugin/row/row0vers.c
  77. 5
      storage/innodb_plugin/srv/srv0srv.c
  78. 4
      storage/innodb_plugin/sync/sync0arr.c
  79. 19
      storage/innodb_plugin/sync/sync0rw.c
  80. 25
      storage/innodb_plugin/trx/trx0trx.c

78
mysql-test/include/have_dbi_dbd-mysql.inc

@ -0,0 +1,78 @@
#
# Originally created by John Embretsen, 2011-01-26.
#
# Checks for the existence of Perl modules DBI and DBD::mysql as seen from the
# perl installation used by "external" executable perl scripts, i.e. scripts
# that are executed as standalone scripts interpreted by the perl installation
# specified by the "shebang" line in the top of these scripts.
#
# If either module is not found, the test will be skipped.
#
# For use in tests that call perl scripts that require these modules.
#
# This file is intended to work on Unix. Windows may need different treatment.
# Reasoning:
# - "shebangs" are not relevant on Windows, but need to be handled here.
# - Perl scripts cannot be made executable on Windows, interpreter must be
# specified.
#
# Note that if there are multiple perl installations and not all have the
# required modules, this check may fail even if the perl in path does have
# the modules available. This may happen if the perl specified by the script's
# shebang (e.g. #!/usr/bin/perl) does not have these modules, and script is
# called without specifying the perl interpreter. However, this will be
# a correct result in cases where a test calls a script with a similar shebang.
#
################################################################################
--source include/not_windows.inc
# We jump through some hoops since there is no direct way to check if an
# external command went OK or not from a mysql-test file:
#
# - In theory, we could do as simple as "exec perl -MDBI -MDBD::mysql -e 1",
# however we cannot check the result (exit code) from within a test script.
# Also, this may not yield the same result as other uses of perl due to the
# shebang issue mentioned above.
# - Instead we use a separate helper perl script that checks for the modules.
# - If the modules are found, the perl script leaves a file which sets a
# variable that can be read by this file.
# If the modules are not found, the perl script does not set this variable,
# but leaves an empty file instead.
#
# This is done because there is apparently no direct way to transfer
# information from perl to the test script itself.
--disable_query_log
--disable_result_log
--disable_warnings
# We do not use embedded perl in this script because that would not have yielded
# correct results for a situation where an external Perl script is called like
# "scriptname" instead of "perl scriptname" and the shebang in the script points
# to a specific perl that may be different than the perl in PATH.
#
# Instead, we call a separate helper script which checks for the modules in its
# own environment. We call it without "perl" in front.
--let $perlChecker= $MYSQLTEST_VARDIR/std_data/checkDBI_DBD-mysql.pl
--let $resultFile= $MYSQL_TMP_DIR/dbidbd-mysql.txt
# Make the script executable and execute it.
--chmod 0755 $perlChecker
--exec $perlChecker
# Source the resulting temporary file and look for a variable being set.
--source $resultFile
if (!$dbidbd) {
--skip Test needs Perl modules DBI and DBD::mysql
}
# Clean up
--remove_file $resultFile
--enable_query_log
--enable_result_log
--enable_warnings

16
mysql-test/include/mysqlhotcopy.inc

@ -4,12 +4,26 @@
--source include/not_windows.inc
--source include/not_embedded.inc
--source include/have_dbi_dbd-mysql.inc
if ($MYSQLHOTCOPY)
if (!$MYSQLHOTCOPY)
{
# Fail the test if the mysqlhotcopy script is missing.
# If the tool's location changes, mysql-test-run.pl must be updated to
# reflect this (look for "MYSQLHOTCOPY").
die due to missing mysqlhotcopy tool;
}
# NOTE (johnemb, 2011-01-26):
# In this test mysqlhotcopy (a perl script) is executed as a standalone
# executable, i.e. not necessarily using the perl interpreter in PATH,
# because that is how the documentation demonstrates it.
#
# We include have_dbi_dbd-mysql.inc above so that the test will
# be skipped if Perl modules required by the mysqlhotcopy tool are not
# found when the script is run this way.
let $MYSQLD_DATADIR= `SELECT @@datadir`;
--disable_warnings
DROP DATABASE IF EXISTS hotcopy_test;

10
mysql-test/mysql-test-run.pl

@ -2141,10 +2141,12 @@ sub environment_setup {
# mysqlhotcopy
# ----------------------------------------------------
my $mysqlhotcopy=
mtr_pl_maybe_exists("$basedir/scripts/mysqlhotcopy");
# Since mysqltest interprets the real path as "false" in an if,
# use 1 ("true") to indicate "not exists" so it can be tested for
$ENV{'MYSQLHOTCOPY'}= $mysqlhotcopy || 1;
mtr_pl_maybe_exists("$basedir/scripts/mysqlhotcopy") ||
mtr_pl_maybe_exists("$path_client_bindir/mysqlhotcopy");
if ($mysqlhotcopy)
{
$ENV{'MYSQLHOTCOPY'}= $mysqlhotcopy;
}
# ----------------------------------------------------
# perror

97
mysql-test/std_data/checkDBI_DBD-mysql.pl

@ -0,0 +1,97 @@
#!/usr/bin/perl
# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; version 2
# of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
################################################################################
#
# This perl script checks for availability of the Perl modules DBI and
# DBD::mysql using the "current" perl interpreter.
#
# Useful for test environment checking before testing executable perl scripts
# in the MySQL Server distribution.
#
# NOTE: The "shebang" on the first line of this script should always point to
# /usr/bin/perl, so that we can use this script to check whether or not we
# support running perl scripts with such a shebang without specifying the
# perl interpreter on the command line. Such a script is mysqlhotcopy.
#
# When run as "checkDBI_DBD-mysql.pl" the shebang line will be evaluated
# and used. When run as "perl checkDBI_DBD-mysql.pl" the shebang line is
# not used.
#
# NOTE: This script will create a temporary file in MTR's tmp dir.
# If modules are found, a mysql-test statement which sets a special
# variable is written to this file. If one of the modules is not found
# (or cannot be loaded), the file will remain empty.
# A test (or include file) which sources that file can then easily do
# an if-check on the special variable to determine success or failure.
#
# Example:
#
# --let $perlChecker= $MYSQLTEST_VARDIR/std_data/checkDBI_DBD-mysql.pl
# --let $resultFile= $MYSQL_TMP_DIR/dbidbd-mysql.txt
# --chmod 0755 $perlChecker
# --exec $perlChecker
# --source $resultFile
# if (!$dbidbd) {
# --skip Test needs Perl modules DBI and DBD::mysql
# }
#
# The calling script is also responsible for cleaning up after use:
#
# --remove_file $resultFile
#
# Windows notes:
# - shebangs may work differently - call this script with "perl " in front.
#
# See mysql-test/include/have_dbi_dbd-mysql.inc for example use of this script.
# This script should be executable for the user running MTR.
#
################################################################################
BEGIN {
# By using eval inside BEGIN we can suppress warnings and continue after.
# We need to catch "Can't locate" as well as "Can't load" errors.
eval{
$FOUND_DBI=0;
$FOUND_DBD_MYSQL=0;
# Check for DBI module:
$FOUND_DBI=1 if require DBI;
# Check for DBD::mysql module
$FOUND_DBD_MYSQL=1 if require DBD::mysql;
};
};
# Open a file to be used for transfer of result back to mysql-test.
# The file must be created whether we write to it or not, otherwise mysql-test
# will complain if trying to source it.
# An empty file indicates failure to load modules.
open(FILE, ">", $ENV{'MYSQL_TMP_DIR'}.'/dbidbd-mysql.txt');
if ($FOUND_DBI && $FOUND_DBD_MYSQL) {
# write a mysql-test command setting a variable to indicate success
print(FILE 'let $dbidbd= FOUND_DBI_DBD-MYSQL;'."\n");
}
# close the file.
close(FILE);
1;

95
mysql-test/suite/innodb/r/innodb_bug30423.result

@ -0,0 +1,95 @@
set global innodb_stats_method = default;
select @@innodb_stats_method;
@@innodb_stats_method
nulls_equal
select count(*) from bug30243_3 where org_id is not NULL;
count(*)
20
select count(*) from bug30243_3 where org_id is NULL;
count(*)
16384
select count(*) from bug30243_2 where org_id is not NULL;
count(*)
224
select count(*) from bug30243_2 where org_id is NULL;
count(*)
65536
select @@innodb_stats_method;
@@innodb_stats_method
nulls_equal
analyze table bug30243_1;
Table Op Msg_type Msg_text
test.bug30243_1 analyze status OK
analyze table bug30243_2;
Table Op Msg_type Msg_text
test.bug30243_2 analyze status OK
analyze table bug30243_3;
Table Op Msg_type Msg_text
test.bug30243_3 analyze status OK
set global innodb_stats_method = "NULL";
ERROR 42000: Variable 'stats_method' can't be set to the value of 'NULL'
set global innodb_stats_method = "nulls_ignored";
select @@innodb_stats_method;
@@innodb_stats_method
nulls_ignored
analyze table bug30243_1;
Table Op Msg_type Msg_text
test.bug30243_1 analyze status OK
analyze table bug30243_2;
Table Op Msg_type Msg_text
test.bug30243_2 analyze status OK
analyze table bug30243_3;
Table Op Msg_type Msg_text
test.bug30243_3 analyze status OK
explain SELECT COUNT(*), 0
FROM bug30243_1 orgs
LEFT JOIN bug30243_3 sa_opportunities
ON orgs.org_id=sa_opportunities.org_id
LEFT JOIN bug30243_2 contacts
ON orgs.org_id=contacts.org_id ;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE orgs index NULL org_id 4 NULL 128 Using index
1 SIMPLE sa_opportunities ref org_id org_id 5 test.orgs.org_id 1 Using index
1 SIMPLE contacts ref contacts$org_id contacts$org_id 5 test.orgs.org_id 1 Using index
select @@innodb_stats_method;
@@innodb_stats_method
nulls_ignored
set global innodb_stats_method = "nulls_unequal";
select @@innodb_stats_method;
@@innodb_stats_method
nulls_unequal
analyze table bug30243_1;
Table Op Msg_type Msg_text
test.bug30243_1 analyze status OK
analyze table bug30243_2;
Table Op Msg_type Msg_text
test.bug30243_2 analyze status OK
analyze table bug30243_3;
Table Op Msg_type Msg_text
test.bug30243_3 analyze status OK
explain SELECT COUNT(*), 0
FROM bug30243_1 orgs
LEFT JOIN bug30243_3 sa_opportunities
ON orgs.org_id=sa_opportunities.org_id
LEFT JOIN bug30243_2 contacts
ON orgs.org_id=contacts.org_id;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE orgs index NULL org_id 4 NULL 128 Using index
1 SIMPLE sa_opportunities ref org_id org_id 5 test.orgs.org_id 1 Using index
1 SIMPLE contacts ref contacts$org_id contacts$org_id 5 test.orgs.org_id 1 Using index
SELECT COUNT(*) FROM table_bug30423 WHERE org_id IS NULL;
COUNT(*)
1024
set global innodb_stats_method = "nulls_unequal";
analyze table table_bug30423;
Table Op Msg_type Msg_text
test.table_bug30423 analyze status OK
set global innodb_stats_method = "nulls_ignored";
analyze table table_bug30423;
Table Op Msg_type Msg_text
test.table_bug30423 analyze status OK
set global innodb_stats_method = nulls_equal;
drop table bug30243_2;
drop table bug30243_1;
drop table bug30243_3;
drop table table_bug30423;

211
mysql-test/suite/innodb/t/innodb_bug30423.test

@ -0,0 +1,211 @@
# Test for Bug #30423, InnoDBs treatment of NULL in index stats causes
# bad "rows examined" estimates.
# Implemented InnoDB system variable "innodb_stats_method" with
# "nulls_equal" (default), "nulls_unequal", and "nulls_ignored" options.
-- source include/have_innodb.inc
let $innodb_stats_method_orig = `select @@innodb_stats_method`;
# default setting for innodb_stats_method is "nulls_equal"
set global innodb_stats_method = default;
select @@innodb_stats_method;
# create three tables, bug30243_1, bug30243_2 and bug30243_3.
# The test scenario is adopted from original bug #30423 report.
# table bug30243_1 and bug30243_3 have many NULL values
-- disable_result_log
-- disable_query_log
DROP TABLE IF EXISTS bug30243_1;
CREATE TABLE bug30243_1 (
org_id int(11) NOT NULL default '0',
UNIQUE KEY (org_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
LOCK TABLES bug30243_1 WRITE;
INSERT INTO bug30243_1 VALUES (11),(15),(16),(17),(19),(20),(21),(23),(24),
(25),(26),(27),(28),(29),(30),(31),(32),(33),(34),(35),(37),(38),(40),(41),
(42),(43),(44),(45),(46),(47),(48),(49),(50),(51),(52),(53),(54),(55),(56),
(57),(58),(59),(60),(61),(62),(63),(64),(65),(66),(67),(68),(69),(70),(71),
(72),(73),(74),(75),(76),(77),(78),(79),(80),(81),(82),(83),(84),(85),(86),
(87),(88),(89),(90),(91),(92),(93),(94),(95),(96),(97),(98),(99),(100),(101),
(102),(103),(104),(105),(106),(107),(108),(109),(110),(111),(112),(113),(114),
(115),(116),(117),(118),(119),(120),(121),(122),(123),(124),(125),(126),(127),
(128),(129),(130),(131),(132),(133),(134),(135),(136),(137),(138),(139),(140),
(141),(142),(143),(144),(145);
UNLOCK TABLES;
DROP TABLE IF EXISTS bug30243_3;
CREATE TABLE bug30243_3 (
org_id int(11) default NULL,
KEY (org_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO bug30243_3 VALUES (NULL);
begin;
let $i=14;
while ($i)
{
INSERT INTO bug30243_3 SELECT NULL FROM bug30243_3;
dec $i;
}
INSERT INTO bug30243_3 VALUES (34),(34),(35),(56),(58),(62),(62),(64),(65),(66),(80),(135),(137),(138),(139),(140),(142),(143),(144),(145);
commit;
DROP TABLE IF EXISTS bug30243_2;
CREATE TABLE bug30243_2 (
org_id int(11) default NULL,
KEY `contacts$org_id` (org_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO bug30243_2 VALUES (NULL);
begin;
let $i=16;
while ($i)
{
INSERT INTO bug30243_2 SELECT NULL FROM bug30243_2;
dec $i;
}
INSERT INTO bug30243_2 VALUES (11),(15),(16),(17),(20),(21),(23),(24),(25),
(26),(27),(28),(29),(30),(31),(32),(33),(34),(37),(38),(40),(41),(42),(43),
(44),(45),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),
(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),
(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),
(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),
(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),
(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(48),
(48),(50),(51),(52),(52),(53),(54),(55),(57),(60),(61),(62),(62),(62),(62),
(62),(63),(64),(64),(65),(66),(66),(67),(68),(69),(70),(71),(72),(73),(74),
(75),(76),(77),(78),(79),(80),(80),(81),(82),(83),(84),(85),(86),(87),(88),
(89),(90),(91),(92),(93),(94),(95),(96),(97),(98),(99),(100),(101),(102),
(103),(104),(105),(106),(107),(108),(109),(110),(111),(112),(113),(114),
(115),(116),(117),(118),(119),(120),(121),(122),(123),(124),(125),(126),
(127),(128),(129),(130),(131),(132),(133),(133),(135),(135),(135),(135),
(136),(136),(138),(138),(139),(139),(139),(140),(141),(141),(142),(143),
(143),(145),(145);
commit;
-- enable_result_log
-- enable_query_log
# check tables's value
select count(*) from bug30243_3 where org_id is not NULL;
select count(*) from bug30243_3 where org_id is NULL;
select count(*) from bug30243_2 where org_id is not NULL;
select count(*) from bug30243_2 where org_id is NULL;
select @@innodb_stats_method;
analyze table bug30243_1;
analyze table bug30243_2;
analyze table bug30243_3;
# Following query plan shows that we over estimate the rows per
# unique value (since there are many NULLs).
# Skip this query log since the stats estimate could vary from runs
-- disable_query_log
-- disable_result_log
explain SELECT COUNT(*), 0
FROM bug30243_1 orgs
LEFT JOIN bug30243_3 sa_opportunities
ON orgs.org_id=sa_opportunities.org_id
LEFT JOIN bug30243_2 contacts
ON orgs.org_id=contacts.org_id ;
-- enable_query_log
-- enable_result_log
# following set operation will fail
#--error ER_WRONG_VALUE_FOR_VAR
--error 1231
set global innodb_stats_method = "NULL";
set global innodb_stats_method = "nulls_ignored";
select @@innodb_stats_method;
# Regenerate the stats with "nulls_ignored" option
analyze table bug30243_1;
analyze table bug30243_2;
analyze table bug30243_3;
# Following query plan shows that we get the correct rows per
# unique value (should be approximately 1 row per value)
explain SELECT COUNT(*), 0
FROM bug30243_1 orgs
LEFT JOIN bug30243_3 sa_opportunities
ON orgs.org_id=sa_opportunities.org_id
LEFT JOIN bug30243_2 contacts
ON orgs.org_id=contacts.org_id ;
select @@innodb_stats_method;
# Try the "nulls_unequal" option
set global innodb_stats_method = "nulls_unequal";
select @@innodb_stats_method;
analyze table bug30243_1;
analyze table bug30243_2;
analyze table bug30243_3;
# Following query plan shows that we get the correct rows per
# unique value (~1)
explain SELECT COUNT(*), 0
FROM bug30243_1 orgs
LEFT JOIN bug30243_3 sa_opportunities
ON orgs.org_id=sa_opportunities.org_id
LEFT JOIN bug30243_2 contacts
ON orgs.org_id=contacts.org_id;
# Create a table with all NULL values, make sure the stats calculation
# does not crash with table of all NULL values
-- disable_query_log
CREATE TABLE table_bug30423 (
org_id int(11) default NULL,
KEY(org_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `table_bug30423` VALUES (NULL);
begin;
let $i=10;
while ($i)
{
INSERT INTO table_bug30423 SELECT NULL FROM table_bug30423;
dec $i;
}
commit;
-- enable_query_log
SELECT COUNT(*) FROM table_bug30423 WHERE org_id IS NULL;
# calculate the statistics for the table for "nulls_ignored" and
# "nulls_unequal" option
set global innodb_stats_method = "nulls_unequal";
analyze table table_bug30423;
set global innodb_stats_method = "nulls_ignored";
analyze table table_bug30423;
eval set global innodb_stats_method = $innodb_stats_method_orig;
drop table bug30243_2;
drop table bug30243_1;
drop table bug30243_3;
drop table table_bug30423;

5
mysql-test/suite/innodb/t/innodb_bug56143.test

@ -8,6 +8,11 @@
-- disable_query_log
-- disable_result_log
if ($VALGRIND_TEST)
{
call mtr.add_suppression("InnoDB: Warning: a long semaphore wait:");
}
SET foreign_key_checks=0;
DROP TABLE IF EXISTS bug56143;
CREATE TABLE `bug56143` (

95
mysql-test/suite/innodb_plugin/r/innodb_bug30423.result

@ -0,0 +1,95 @@
set global innodb_stats_method = default;
select @@innodb_stats_method;
@@innodb_stats_method
nulls_equal
select count(*) from bug30243_3 where org_id is not NULL;
count(*)
20
select count(*) from bug30243_3 where org_id is NULL;
count(*)
16384
select count(*) from bug30243_2 where org_id is not NULL;
count(*)
224
select count(*) from bug30243_2 where org_id is NULL;
count(*)
65536
select @@innodb_stats_method;
@@innodb_stats_method
nulls_equal
analyze table bug30243_1;
Table Op Msg_type Msg_text
test.bug30243_1 analyze status OK
analyze table bug30243_2;
Table Op Msg_type Msg_text
test.bug30243_2 analyze status OK
analyze table bug30243_3;
Table Op Msg_type Msg_text
test.bug30243_3 analyze status OK
set global innodb_stats_method = "NULL";
ERROR 42000: Variable 'stats_method' can't be set to the value of 'NULL'
set global innodb_stats_method = "nulls_ignored";
select @@innodb_stats_method;
@@innodb_stats_method
nulls_ignored
analyze table bug30243_1;
Table Op Msg_type Msg_text
test.bug30243_1 analyze status OK
analyze table bug30243_2;
Table Op Msg_type Msg_text
test.bug30243_2 analyze status OK
analyze table bug30243_3;
Table Op Msg_type Msg_text
test.bug30243_3 analyze status OK
explain SELECT COUNT(*), 0
FROM bug30243_1 orgs
LEFT JOIN bug30243_3 sa_opportunities
ON orgs.org_id=sa_opportunities.org_id
LEFT JOIN bug30243_2 contacts
ON orgs.org_id=contacts.org_id ;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE orgs index NULL org_id 4 NULL 128 Using index
1 SIMPLE sa_opportunities ref org_id org_id 5 test.orgs.org_id 1 Using index
1 SIMPLE contacts ref contacts$org_id contacts$org_id 5 test.orgs.org_id 1 Using index
select @@innodb_stats_method;
@@innodb_stats_method
nulls_ignored
set global innodb_stats_method = "nulls_unequal";
select @@innodb_stats_method;
@@innodb_stats_method
nulls_unequal
analyze table bug30243_1;
Table Op Msg_type Msg_text
test.bug30243_1 analyze status OK
analyze table bug30243_2;
Table Op Msg_type Msg_text
test.bug30243_2 analyze status OK
analyze table bug30243_3;
Table Op Msg_type Msg_text
test.bug30243_3 analyze status OK
explain SELECT COUNT(*), 0
FROM bug30243_1 orgs
LEFT JOIN bug30243_3 sa_opportunities
ON orgs.org_id=sa_opportunities.org_id
LEFT JOIN bug30243_2 contacts
ON orgs.org_id=contacts.org_id;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE orgs index NULL org_id 4 NULL 128 Using index
1 SIMPLE sa_opportunities ref org_id org_id 5 test.orgs.org_id 1 Using index
1 SIMPLE contacts ref contacts$org_id contacts$org_id 5 test.orgs.org_id 1 Using index
SELECT COUNT(*) FROM table_bug30423 WHERE org_id IS NULL;
COUNT(*)
1024
set global innodb_stats_method = "nulls_unequal";
analyze table table_bug30423;
Table Op Msg_type Msg_text
test.table_bug30423 analyze status OK
set global innodb_stats_method = "nulls_ignored";
analyze table table_bug30423;
Table Op Msg_type Msg_text
test.table_bug30423 analyze status OK
set global innodb_stats_method = nulls_equal;
drop table bug30243_2;
drop table bug30243_1;
drop table bug30243_3;
drop table table_bug30423;

211
mysql-test/suite/innodb_plugin/t/innodb_bug30423.test

@ -0,0 +1,211 @@
# Test for Bug #30423, InnoDBs treatment of NULL in index stats causes
# bad "rows examined" estimates.
# Implemented InnoDB system variable "innodb_stats_method" with
# "nulls_equal" (default), "nulls_unequal", and "nulls_ignored" options.
-- source include/have_innodb_plugin.inc
let $innodb_stats_method_orig = `select @@innodb_stats_method`;
# default setting for innodb_stats_method is "nulls_equal"
set global innodb_stats_method = default;
select @@innodb_stats_method;
# create three tables, bug30243_1, bug30243_2 and bug30243_3.
# The test scenario is adopted from original bug #30423 report.
# table bug30243_1 and bug30243_3 have many NULL values
-- disable_result_log
-- disable_query_log
DROP TABLE IF EXISTS bug30243_1;
CREATE TABLE bug30243_1 (
org_id int(11) NOT NULL default '0',
UNIQUE KEY (org_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
LOCK TABLES bug30243_1 WRITE;
INSERT INTO bug30243_1 VALUES (11),(15),(16),(17),(19),(20),(21),(23),(24),
(25),(26),(27),(28),(29),(30),(31),(32),(33),(34),(35),(37),(38),(40),(41),
(42),(43),(44),(45),(46),(47),(48),(49),(50),(51),(52),(53),(54),(55),(56),
(57),(58),(59),(60),(61),(62),(63),(64),(65),(66),(67),(68),(69),(70),(71),
(72),(73),(74),(75),(76),(77),(78),(79),(80),(81),(82),(83),(84),(85),(86),
(87),(88),(89),(90),(91),(92),(93),(94),(95),(96),(97),(98),(99),(100),(101),
(102),(103),(104),(105),(106),(107),(108),(109),(110),(111),(112),(113),(114),
(115),(116),(117),(118),(119),(120),(121),(122),(123),(124),(125),(126),(127),
(128),(129),(130),(131),(132),(133),(134),(135),(136),(137),(138),(139),(140),
(141),(142),(143),(144),(145);
UNLOCK TABLES;
DROP TABLE IF EXISTS bug30243_3;
CREATE TABLE bug30243_3 (
org_id int(11) default NULL,
KEY (org_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO bug30243_3 VALUES (NULL);
begin;
let $i=14;
while ($i)
{
INSERT INTO bug30243_3 SELECT NULL FROM bug30243_3;
dec $i;
}
INSERT INTO bug30243_3 VALUES (34),(34),(35),(56),(58),(62),(62),(64),(65),(66),(80),(135),(137),(138),(139),(140),(142),(143),(144),(145);
commit;
DROP TABLE IF EXISTS bug30243_2;
CREATE TABLE bug30243_2 (
org_id int(11) default NULL,
KEY `contacts$org_id` (org_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO bug30243_2 VALUES (NULL);
begin;
let $i=16;
while ($i)
{
INSERT INTO bug30243_2 SELECT NULL FROM bug30243_2;
dec $i;
}
INSERT INTO bug30243_2 VALUES (11),(15),(16),(17),(20),(21),(23),(24),(25),
(26),(27),(28),(29),(30),(31),(32),(33),(34),(37),(38),(40),(41),(42),(43),
(44),(45),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),
(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),
(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),
(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),
(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),
(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(48),
(48),(50),(51),(52),(52),(53),(54),(55),(57),(60),(61),(62),(62),(62),(62),
(62),(63),(64),(64),(65),(66),(66),(67),(68),(69),(70),(71),(72),(73),(74),
(75),(76),(77),(78),(79),(80),(80),(81),(82),(83),(84),(85),(86),(87),(88),
(89),(90),(91),(92),(93),(94),(95),(96),(97),(98),(99),(100),(101),(102),
(103),(104),(105),(106),(107),(108),(109),(110),(111),(112),(113),(114),
(115),(116),(117),(118),(119),(120),(121),(122),(123),(124),(125),(126),
(127),(128),(129),(130),(131),(132),(133),(133),(135),(135),(135),(135),
(136),(136),(138),(138),(139),(139),(139),(140),(141),(141),(142),(143),
(143),(145),(145);
commit;
-- enable_result_log
-- enable_query_log
# check tables's value
select count(*) from bug30243_3 where org_id is not NULL;
select count(*) from bug30243_3 where org_id is NULL;
select count(*) from bug30243_2 where org_id is not NULL;
select count(*) from bug30243_2 where org_id is NULL;
select @@innodb_stats_method;
analyze table bug30243_1;
analyze table bug30243_2;
analyze table bug30243_3;
# Following query plan shows that we over estimate the rows per
# unique value (since there are many NULLs).
# Skip this query log since the stats estimate could vary from runs
-- disable_query_log
-- disable_result_log
explain SELECT COUNT(*), 0
FROM bug30243_1 orgs
LEFT JOIN bug30243_3 sa_opportunities
ON orgs.org_id=sa_opportunities.org_id
LEFT JOIN bug30243_2 contacts
ON orgs.org_id=contacts.org_id ;
-- enable_query_log
-- enable_result_log
# following set operation will fail
#--error ER_WRONG_VALUE_FOR_VAR
--error 1231
set global innodb_stats_method = "NULL";
set global innodb_stats_method = "nulls_ignored";
select @@innodb_stats_method;
# Regenerate the stats with "nulls_ignored" option
analyze table bug30243_1;
analyze table bug30243_2;
analyze table bug30243_3;
# Following query plan shows that we get the correct rows per
# unique value (should be approximately 1 row per value)
explain SELECT COUNT(*), 0
FROM bug30243_1 orgs
LEFT JOIN bug30243_3 sa_opportunities
ON orgs.org_id=sa_opportunities.org_id
LEFT JOIN bug30243_2 contacts
ON orgs.org_id=contacts.org_id ;
select @@innodb_stats_method;
# Try the "nulls_unequal" option
set global innodb_stats_method = "nulls_unequal";
select @@innodb_stats_method;
analyze table bug30243_1;
analyze table bug30243_2;
analyze table bug30243_3;
# Following query plan shows that we get the correct rows per
# unique value (~1)
explain SELECT COUNT(*), 0
FROM bug30243_1 orgs
LEFT JOIN bug30243_3 sa_opportunities
ON orgs.org_id=sa_opportunities.org_id
LEFT JOIN bug30243_2 contacts
ON orgs.org_id=contacts.org_id;
# Create a table with all NULL values, make sure the stats calculation
# does not crash with table of all NULL values
-- disable_query_log
CREATE TABLE table_bug30423 (
org_id int(11) default NULL,
KEY(org_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `table_bug30423` VALUES (NULL);
begin;
let $i=10;
while ($i)
{
INSERT INTO table_bug30423 SELECT NULL FROM table_bug30423;
dec $i;
}
commit;
-- enable_query_log
SELECT COUNT(*) FROM table_bug30423 WHERE org_id IS NULL;
# calculate the statistics for the table for "nulls_ignored" and
# "nulls_unequal" option
set global innodb_stats_method = "nulls_unequal";
analyze table table_bug30423;
set global innodb_stats_method = "nulls_ignored";
analyze table table_bug30423;
eval set global innodb_stats_method = $innodb_stats_method_orig;
drop table bug30243_2;
drop table bug30243_1;
drop table bug30243_3;
drop table table_bug30423;

5
mysql-test/suite/innodb_plugin/t/innodb_bug56143.test

@ -8,6 +8,11 @@
-- disable_query_log
-- disable_result_log
if ($VALGRIND_TEST)
{
call mtr.add_suppression("InnoDB: Warning: a long semaphore wait:");
}
SET foreign_key_checks=0;
DROP TABLE IF EXISTS bug56143_1;

4
mysql-test/suite/parts/inc/partition_check_drop.inc

@ -66,10 +66,10 @@ if ($found_garbage)
}
# Do a manual cleanup, because the following tests should not suffer from
# remaining files
--exec rm -f $MYSQLD_DATADIR/test/t1* || true
--remove_files_wildcard $MYSQLD_DATADIR/test t1*
if ($with_directories)
{
--exec rm -f $MYSQLTEST_VARDIR/tmp/t1* || true
--remove_files_wildcard $MYSQLTEST_VARDIR/tmp t1*
}
}
--enable_query_log

13
mysql-test/suite/parts/inc/partition_layout_check1.inc

@ -29,14 +29,10 @@ DELETE FROM t0_definition;
let $MYSQLD_DATADIR= `select LEFT(@@datadir, LENGTH(@@datadir)-1)`;
#echo MYSQLD_DATADIR: $MYSQLD_DATADIR;
# Dump the current definition of the table t1 to tmp1
# This complicated method - let another mysqltest collect the output - is used
# because of two reasons
# Save the current definition of the table t1
# - SHOW CREATE TABLE t1 is at least currently most probably more reliable than
# the corresponding SELECT on the INFORMATION_SCHEMA
# - SHOW CREATE TABLE .. cannot write its out put into a file like SELECT
let $show_file= $MYSQLD_DATADIR/test/tmp1;
--exec echo "SHOW CREATE TABLE t1; exit; " | $MYSQL_TEST > $show_file 2>&1
let $show_create= `SHOW CREATE TABLE t1`;
if ($do_file_tests)
{
# List the files belonging to the table t1
@ -57,12 +53,13 @@ if (!$do_file_tests)
# Insert the current definition of the table t1 into t0_definition
eval INSERT INTO t0_definition SET state = 'old',
create_command = load_file('$show_file'),
create_command = "$show_create",
file_list = @aux;
# Print the create table statement into the protocol
# Added the concat to avoid changing the result files
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR '\r' ''
SELECT create_command FROM t0_definition WHERE state = 'old';
SELECT concat('SHOW CREATE TABLE t1;\nTable\tCreate Table\n',create_command,'\n') as `create_command` FROM t0_definition WHERE state = 'old';
if ($do_file_tests)
{
# We stored the list of files, therefore printing the content makes sense

7
mysql-test/suite/parts/inc/partition_layout_check2.inc

@ -28,9 +28,8 @@ DELETE FROM t0_definition WHERE state = 'new';
let $MYSQLD_DATADIR= `select LEFT(@@datadir, LENGTH(@@datadir)-1)`;
#echo MYSQLD_DATADIR: $MYSQLD_DATADIR;
# Dump the current definition of the table t1 to tmp1
let $show_file= $MYSQLD_DATADIR/test/tmp1;
--exec echo "SHOW CREATE TABLE t1; exit; " | $MYSQL_TEST > $show_file 2>&1
# Save the current definition of the table t1
let $show_create= `SHOW CREATE TABLE t1`;
if ($do_file_tests)
{
@ -52,7 +51,7 @@ if (!$do_file_tests)
# Insert the current definition of the table t1 into t0_definition
eval INSERT INTO t0_definition SET state = 'new',
create_command = load_file('$show_file'),
create_command = "$show_create",
file_list = @aux;
# Print the old and new table layout, if they differ

2
mysql-test/suite/parts/r/partition_recover_myisam.result

@ -1,4 +1,4 @@
call mtr.add_suppression("./test/t1_will_crash");
call mtr.add_suppression("t1_will_crash");
call mtr.add_suppression("Got an error from unknown thread, ha_myisam.cc");
CREATE TABLE t1_will_crash (a INT, KEY (a)) ENGINE=MyISAM;
INSERT INTO t1_will_crash VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11);

2
mysql-test/suite/parts/t/partition_debug_sync_innodb.test

@ -14,6 +14,7 @@ partition by range (a)
insert into t1 values (1), (11), (21), (33);
SELECT * FROM t1;
SHOW CREATE TABLE t1;
--replace_result #p# #P#
--list_files $MYSQLD_DATADIR/test
SET DEBUG_SYNC='before_open_in_get_all_tables SIGNAL parked WAIT_FOR open';
@ -36,6 +37,7 @@ ALTER TABLE t1 REORGANIZE PARTITION p0 INTO
disconnect con1;
connection default;
--reap
--replace_result #p# #P#
--list_files $MYSQLD_DATADIR/test
SHOW CREATE TABLE t1;
SELECT * FROM t1;

6
mysql-test/suite/parts/t/partition_recover_myisam.test

@ -1,6 +1,6 @@
# test the auto-recover (--myisam-recover) of partitioned myisam tables
call mtr.add_suppression("./test/t1_will_crash");
call mtr.add_suppression("t1_will_crash");
call mtr.add_suppression("Got an error from unknown thread, ha_myisam.cc");
--source include/have_partition.inc
@ -20,6 +20,8 @@ FLUSH TABLES;
let $MYSQLD_DATADIR= `select @@datadir`;
--remove_file $MYSQLD_DATADIR/test/t1_will_crash.MYI
--copy_file std_data/corrupt_t1.MYI $MYSQLD_DATADIR/test/t1_will_crash.MYI
--replace_result \\ /
--replace_regex /Table '.*data/Table './
SELECT * FROM t1_will_crash;
DROP TABLE t1_will_crash;
CREATE TABLE t1_will_crash (a INT, KEY (a))
@ -33,5 +35,7 @@ FLUSH TABLES;
--echo # head -c1024 t1#P#p1.MYI > corrupt_t1#P#p1.MYI
--remove_file $MYSQLD_DATADIR/test/t1_will_crash#P#p1.MYI
--copy_file std_data/corrupt_t1#P#p1.MYI $MYSQLD_DATADIR/test/t1_will_crash#P#p1.MYI
--replace_result \\ /
--replace_regex /Table '.*data/Table './
SELECT * FROM t1_will_crash;
DROP TABLE t1_will_crash;

4
mysql-test/suite/parts/t/partition_special_innodb.test

@ -58,8 +58,8 @@ ENGINE = InnoDB
PARTITION BY HASH (a)
PARTITIONS 2;
connect (con1,127.0.0.1,root,,test,$MASTER_MYPORT,);
connect (con2,127.0.0.1,root,,test,$MASTER_MYPORT,);
connect (con1, localhost, root,,);
connect (con2, localhost, root,,);
--connection con1
SET autocommit=OFF;

2
mysql-test/suite/sys_vars/r/general_log_file_basic.result

@ -16,4 +16,4 @@ FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME='general_log_file';
@@global.general_log_file = VARIABLE_VALUE
1
SET @@global.general_log_file= 'test.log';
SET @@global.general_log_file= 'start_value';

2
mysql-test/suite/sys_vars/r/log_output_func.result

@ -52,7 +52,7 @@ count(*)
DROP TABLE t1;
connection default;
SET @@global.general_log= 'OFF';
SET @@global.general_log_file= '/home/horst/bzr/5.1-52501/mysql-test/var/mysqld.1/mysqld.log';
SET @@global.general_log_file= 'start_general_log_file';
SET @@global.log_output= @start_value;
SET @@global.general_log= @start_general_log;
SET @@global.general_log= 'ON';

2
mysql-test/suite/sys_vars/r/slow_query_log_file_basic.result

@ -14,4 +14,4 @@ FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME='slow_query_log_file';
@@global.slow_query_log_file = VARIABLE_VALUE
1
SET @@global.slow_query_log_file= 'slowtest.log';
SET @@global.slow_query_log_file= 'start_value';

2
mysql-test/suite/sys_vars/t/div_precision_increment_func.test

@ -19,7 +19,7 @@
# #
################################################################################
let $save_div_precision_increment = `SELECT @@global.div_precision_increment`
let $save_div_precision_increment = `SELECT @@global.div_precision_increment`;
#SET @save_div_precision_increment = @@global.div_precision_increment;

1
mysql-test/suite/sys_vars/t/general_log_file_basic.test

@ -70,6 +70,7 @@ FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME='general_log_file';
#SET @@global.general_log_file= @start_value;
--replace_result $start_value start_value
eval SET @@global.general_log_file= '$start_value';
#####################################################

1
mysql-test/suite/sys_vars/t/log_output_func.test

@ -115,6 +115,7 @@ file_exists $MYSQLTEST_VARDIR/run/mytest.log ;
connection default;
SET @@global.general_log= 'OFF';
#SET @@global.general_log_file= @start_general_log_file;
--replace_result $start_general_log_file start_general_log_file
eval SET @@global.general_log_file= '$start_general_log_file';
SET @@global.log_output= @start_value;
SET @@global.general_log= @start_general_log;

1
mysql-test/suite/sys_vars/t/slow_query_log_file_basic.test

@ -68,6 +68,7 @@ FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME='slow_query_log_file';
#SET @@global.slow_query_log_file= @start_value;
--replace_result $start_value start_value
eval SET @@global.slow_query_log_file= '$start_value';
#SELECT @start_value;
#####################################################

2
mysql-test/t/disabled.def

@ -11,7 +11,5 @@
##############################################################################
kill : Bug#37780 2008-12-03 HHunger need some changes to be robust enough for pushbuild.
query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails sporadically
main.mysqlhotcopy_myisam : Bug#56817 2010-10-21 anitha mysqlhotcopy* fails
main.mysqlhotcopy_archive: Bug#56817 2010-10-21 anitha mysqlhotcopy* fails
log_tables-big : Bug#48646 2010-11-15 mattiasj report already exists
read_many_rows_innodb : Bug#37635 2010-11-15 mattiasj report already exists

2
sql/item.h

@ -1,4 +1,4 @@
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

2
sql/item_func.h

@ -1,4 +1,4 @@
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

2
sql/item_timefunc.h

@ -1,4 +1,4 @@
/* Copyright (C) 2000-2006 MySQL AB
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

2
sql/sql_partition.cc

@ -1,4 +1,4 @@
/* Copyright 2005-2008 MySQL AB, 2008 Sun Microsystems, Inc.
/* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

2
sql/table.cc

@ -1,4 +1,4 @@
/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

156
storage/innobase/btr/btr0cur.c

@ -66,6 +66,13 @@ this many index pages */
/*--------------------------------------*/
#define BTR_BLOB_HDR_SIZE 8
/* Estimated table level stats from sampled value. */
#define BTR_TABLE_STATS_FROM_SAMPLE(value, index, ext_size, not_empty) \
((value * (ib_longlong) index->stat_n_leaf_pages \
+ BTR_KEY_VAL_ESTIMATE_N_PAGES - 1 + ext_size \
+ not_empty) \
/ (BTR_KEY_VAL_ESTIMATE_N_PAGES + ext_size))
/***********************************************************************
Marks all extern fields in a record as owned by the record. This function
should be called if the delete mark of a record is removed: a not delete
@ -2834,10 +2841,55 @@ btr_estimate_n_rows_in_range(
}
}
/***********************************************************************
Record the number of non_null key values in a given index for
each n-column prefix of the index where n < dict_index_get_n_unique(index).
The estimates are eventually stored in the array:
index->stat_n_non_null_key_vals. */
static
void
btr_record_not_null_field_in_rec(
/*=============================*/
rec_t* rec, /* in: physical record */
ulint n_unique, /* in: dict_index_get_n_unique(index),
number of columns uniquely determine
an index entry */
const ulint* offsets, /* in: rec_get_offsets(rec, index),
its size could be for all fields or
that of "n_unique" */
ib_longlong* n_not_null) /* in/out: array to record number of
not null rows for n-column prefix */
{
ulint i;
ut_ad(rec_offs_n_fields(offsets) >= n_unique);
if (n_not_null == NULL) {
return;
}
for (i = 0; i < n_unique; i++) {
ulint rec_len;
byte* field;
field = rec_get_nth_field(rec, offsets, i, &rec_len);
if (rec_len != UNIV_SQL_NULL) {
n_not_null[i]++;
} else {
/* Break if we hit the first NULL value */
break;
}
}
}
/***********************************************************************
Estimates the number of different key values in a given index, for
each n-column prefix of the index where n <= dict_index_get_n_unique(index).
The estimates are stored in the array index->stat_n_diff_key_vals. */
The estimates are stored in the array index->stat_n_diff_key_vals.
If innodb_stats_method is "nulls_ignored", we also record the number of
non-null values for each prefix and store the estimates in
array index->stat_n_non_null_key_vals. */
void
btr_estimate_number_of_different_key_vals(
@ -2851,6 +2903,8 @@ btr_estimate_number_of_different_key_vals(
ulint matched_fields;
ulint matched_bytes;
ib_longlong* n_diff;
ib_longlong* n_not_null;
ibool stats_null_not_equal;
ulint not_empty_flag = 0;
ulint total_external_size = 0;
ulint i;
@ -2858,24 +2912,47 @@ btr_estimate_number_of_different_key_vals(
ulint add_on;
mtr_t mtr;
mem_heap_t* heap = NULL;
ulint offsets_rec_[REC_OFFS_NORMAL_SIZE];
ulint offsets_next_rec_[REC_OFFS_NORMAL_SIZE];
ulint* offsets_rec = offsets_rec_;
ulint* offsets_next_rec= offsets_next_rec_;
*offsets_rec_ = (sizeof offsets_rec_) / sizeof *offsets_rec_;
*offsets_next_rec_
= (sizeof offsets_next_rec_) / sizeof *offsets_next_rec_;
ulint* offsets_rec = NULL;
ulint* offsets_next_rec = NULL;
n_cols = dict_index_get_n_unique(index);
n_diff = mem_alloc((n_cols + 1) * sizeof(ib_longlong));
heap = mem_heap_create((sizeof *n_diff + sizeof *n_not_null)
* (n_cols + 1)
+ dict_index_get_n_fields(index)
* (sizeof *offsets_rec
+ sizeof *offsets_next_rec));
n_diff = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_longlong));
n_not_null = NULL;
/* Check srv_innodb_stats_method setting, and decide whether we
need to record non-null value and also decide if NULL is
considered equal (by setting stats_null_not_equal value) */
switch (srv_innodb_stats_method) {
case SRV_STATS_NULLS_IGNORED:
n_not_null = mem_heap_zalloc(heap, (n_cols + 1)
* sizeof *n_not_null);
/* fall through */
case SRV_STATS_NULLS_UNEQUAL:
/* for both SRV_STATS_NULLS_IGNORED and SRV_STATS_NULLS_UNEQUAL
case, we will treat NULLs as unequal value */
stats_null_not_equal = TRUE;
break;
memset(n_diff, 0, (n_cols + 1) * sizeof(ib_longlong));
case SRV_STATS_NULLS_EQUAL:
stats_null_not_equal = FALSE;
break;
default:
ut_error;
}
/* We sample some pages in the index to get an estimate */
for (i = 0; i < BTR_KEY_VAL_ESTIMATE_N_PAGES; i++) {
rec_t* supremum;
mtr_start(&mtr);
btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr);
@ -2888,18 +2965,25 @@ btr_estimate_number_of_different_key_vals(
page = btr_cur_get_page(&cursor);
supremum = page_get_supremum_rec(page);
rec = page_rec_get_next(page_get_infimum_rec(page));
if (rec != supremum) {
if (!page_rec_is_supremum(rec)) {
not_empty_flag = 1;
offsets_rec = rec_get_offsets(rec, index, offsets_rec,
ULINT_UNDEFINED, &heap);
if (n_not_null) {
btr_record_not_null_field_in_rec(
rec, n_cols, offsets_rec, n_not_null);
}
}
while (rec != supremum) {
while (!page_rec_is_supremum(rec)) {
rec_t* next_rec = page_rec_get_next(rec);
if (next_rec == supremum) {
if (page_rec_is_supremum(next_rec)) {
total_external_size +=
btr_rec_get_externally_stored_len(
rec, offsets_rec);
break;
}
@ -2907,11 +2991,13 @@ btr_estimate_number_of_different_key_vals(
matched_bytes = 0;
offsets_next_rec = rec_get_offsets(next_rec, index,
offsets_next_rec,
n_cols, &heap);
ULINT_UNDEFINED,
&heap);
cmp_rec_rec_with_match(rec, next_rec,
offsets_rec, offsets_next_rec,
index, &matched_fields,
index, stats_null_not_equal,
&matched_fields,
&matched_bytes);
for (j = matched_fields + 1; j <= n_cols; j++) {
@ -2921,6 +3007,12 @@ btr_estimate_number_of_different_key_vals(
n_diff[j]++;
}
if (n_not_null) {
btr_record_not_null_field_in_rec(
next_rec, n_cols, offsets_next_rec,
n_not_null);
}
total_external_size
+= btr_rec_get_externally_stored_len(
rec, offsets_rec);
@ -2955,10 +3047,6 @@ btr_estimate_number_of_different_key_vals(
}
}
offsets_rec = rec_get_offsets(rec, index, offsets_rec,
ULINT_UNDEFINED, &heap);
total_external_size += btr_rec_get_externally_stored_len(
rec, offsets_rec);
mtr_commit(&mtr);
}
@ -2971,14 +3059,8 @@ btr_estimate_number_of_different_key_vals(
included in index->stat_n_leaf_pages) */
for (j = 0; j <= n_cols; j++) {
index->stat_n_diff_key_vals[j]
= ((n_diff[j]
* (ib_longlong)index->stat_n_leaf_pages
+ BTR_KEY_VAL_ESTIMATE_N_PAGES - 1
+ total_external_size
+ not_empty_flag)
/ (BTR_KEY_VAL_ESTIMATE_N_PAGES
+ total_external_size));
index->stat_n_diff_key_vals[j] = BTR_TABLE_STATS_FROM_SAMPLE(
n_diff[j], index, total_external_size, not_empty_flag);
/* If the tree is small, smaller than
10 * BTR_KEY_VAL_ESTIMATE_N_PAGES + total_external_size, then
@ -2997,12 +3079,20 @@ btr_estimate_number_of_different_key_vals(
}
index->stat_n_diff_key_vals[j] += add_on;
}
mem_free(n_diff);
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
/* Update the stat_n_non_null_key_vals[] with our
sampled result. stat_n_non_null_key_vals[] is created
and initialized to zero in dict_index_add_to_cache(),
along with stat_n_diff_key_vals[] array */
if (n_not_null != NULL && (j < n_cols)) {
index->stat_n_non_null_key_vals[j] =
BTR_TABLE_STATS_FROM_SAMPLE(
n_not_null[j], index,
total_external_size, not_empty_flag);
}
}
mem_heap_free(heap);
}
/*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/

10
storage/innobase/dict/dict0dict.c

@ -1358,6 +1358,12 @@ dict_index_add_to_cache(
new_index->heap,
(1 + dict_index_get_n_unique(new_index))
* sizeof(ib_longlong));
new_index->stat_n_non_null_key_vals = mem_heap_zalloc(
new_index->heap,
(1 + dict_index_get_n_unique(new_index))
* sizeof(*new_index->stat_n_non_null_key_vals));
/* Give some sensible values to stat_n_... in case we do
not calculate statistics quickly enough */
@ -3817,6 +3823,10 @@ dict_update_statistics_low(
for (i = dict_index_get_n_unique(index); i; ) {
index->stat_n_diff_key_vals[i--] = 1;
}
memset(index->stat_n_non_null_key_vals, 0,
(1 + dict_index_get_n_unique(index))
* sizeof(*index->stat_n_non_null_key_vals));
}
index = dict_table_get_next_index(index);

95
storage/innobase/handler/ha_innodb.cc

@ -130,6 +130,25 @@ static my_bool innobase_adaptive_hash_index = TRUE;
static char* internal_innobase_data_file_path = NULL;
/* Possible values for system variable "innodb_stats_method". The values
are defined the same as its corresponding MyISAM system variable
"myisam_stats_method"(see "myisam_stats_method_names"), for better usability */
static const char* innodb_stats_method_names[] = {
"nulls_equal",
"nulls_unequal",
"nulls_ignored",
NullS
};
/* Used to define an enumerate type of the system variable innodb_stats_method.
This is the same as "myisam_stats_method_typelib" */
static TYPELIB innodb_stats_method_typelib = {
array_elements(innodb_stats_method_names) - 1,
"innodb_stats_method_typelib",
innodb_stats_method_names,
NULL
};
/* The following counter is used to convey information to InnoDB
about server activity: in selects it is not sensible to call
srv_active_wake_master_thread after each fetch or search, we only do
@ -6362,6 +6381,65 @@ ha_innobase::read_time(
return(ranges + (double) rows / (double) total_rows * time_for_scan);
}
/*************************************************************************
Calculate Record Per Key value. Need to exclude the NULL value if
innodb_stats_method is set to "nulls_ignored" */
static
ha_rows
innodb_rec_per_key(
/*===============*/
/* out: estimated record per key
value */
dict_index_t* index, /* in: dict_index_t structure */
ulint i, /* in: the column we are
calculating rec per key */
ha_rows records) /* in: estimated total records */
{
ha_rows rec_per_key;
ut_ad(i < dict_index_get_n_unique(index));
/* Note the stat_n_diff_key_vals[] stores the diff value with
n-prefix indexing, so it is always stat_n_diff_key_vals[i + 1] */
if (index->stat_n_diff_key_vals[i + 1] == 0) {
rec_per_key = records;
} else if (srv_innodb_stats_method == SRV_STATS_NULLS_IGNORED) {
ib_longlong num_null;
/* Number of rows with NULL value in this
field */
num_null = records - index->stat_n_non_null_key_vals[i];
/* In theory, index->stat_n_non_null_key_vals[i]
should always be less than the number of records.
Since this is statistics value, the value could
have slight discrepancy. But we will make sure
the number of null values is not a negative number. */
num_null = (num_null < 0) ? 0 : num_null;
/* If the number of NULL values is the same as or
large than that of the distinct values, we could
consider that the table consists mostly of NULL value.
Set rec_per_key to 1. */
if (index->stat_n_diff_key_vals[i + 1] <= num_null) {
rec_per_key = 1;
} else {
/* Need to exclude rows with NULL values from
rec_per_key calculation */
rec_per_key = (ha_rows)(
(records - num_null)
/ (index->stat_n_diff_key_vals[i + 1]
- num_null));
}
} else {
rec_per_key = (ha_rows)
(records / index->stat_n_diff_key_vals[i + 1]);
}
return(rec_per_key);
}
/*************************************************************************
Returns statistics information of the table to the MySQL interpreter,
in various fields of the handle object. */
@ -6568,13 +6646,8 @@ ha_innobase::info_low(
break;
}
if (index->stat_n_diff_key_vals[j + 1] == 0) {
rec_per_key = stats.records;
} else {
rec_per_key = (ha_rows)(stats.records /
index->stat_n_diff_key_vals[j + 1]);
}
rec_per_key = innodb_rec_per_key(
index, j, stats.records);
/* Since MySQL seems to favor table scans
too much over index searches, we pretend
@ -8990,6 +9063,13 @@ static MYSQL_SYSVAR_LONG(autoinc_lock_mode, innobase_autoinc_lock_mode,
AUTOINC_OLD_STYLE_LOCKING, /* Minimum value */
AUTOINC_NO_LOCKING, 0); /* Maximum value */
static MYSQL_SYSVAR_ENUM(stats_method, srv_innodb_stats_method,
PLUGIN_VAR_RQCMDARG,
"Specifies how InnoDB index statistics collection code should "
"treat NULLs. Possible values are NULLS_EQUAL (default), "
"NULLS_UNEQUAL and NULLS_IGNORED",
NULL, NULL, SRV_STATS_NULLS_EQUAL, &innodb_stats_method_typelib);
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
static MYSQL_SYSVAR_UINT(change_buffering_debug, ibuf_debug,
PLUGIN_VAR_RQCMDARG,
@ -9031,6 +9111,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(stats_on_metadata),
MYSQL_SYSVAR(use_legacy_cardinality_algorithm),
MYSQL_SYSVAR(adaptive_hash_index),
MYSQL_SYSVAR(stats_method),
MYSQL_SYSVAR(status_file),
MYSQL_SYSVAR(support_xa),
MYSQL_SYSVAR(sync_spin_loops),

5
storage/innobase/include/btr0cur.h

@ -404,7 +404,10 @@ btr_estimate_n_rows_in_range(
/***********************************************************************
Estimates the number of different key values in a given index, for
each n-column prefix of the index where n <= dict_index_get_n_unique(index).
The estimates are stored in the array index->stat_n_diff_key_vals. */
The estimates are stored in the array index->stat_n_diff_key_vals.
If innodb_stats_method is nulls_ignored, we also record the number of
non-null values for each prefix and stored the estimates in
array index->stat_n_non_null_key_vals. */
void
btr_estimate_number_of_different_key_vals(

6
storage/innobase/include/dict0mem.h

@ -222,6 +222,12 @@ struct dict_index_struct{
for this index, for each n-column prefix
where n <= dict_get_n_unique(index); we
periodically calculate new estimates */
ib_longlong* stat_n_non_null_key_vals;
/* approximate number of non-null key values
for this index, for each column where
n < dict_get_n_unique(index); This
is used when innodb_stats_method is
"nulls_ignored". */
ulint stat_index_size;
/* approximate index size in database pages */
ulint stat_n_leaf_pages;

5
storage/innobase/include/dict0types.h

@ -16,11 +16,6 @@ typedef struct dict_index_struct dict_index_t;
typedef struct dict_table_struct dict_table_t;
typedef struct dict_foreign_struct dict_foreign_t;
/* A cluster object is a table object with the type field set to
DICT_CLUSTERED */
typedef dict_table_t dict_cluster_t;
typedef struct ind_node_struct ind_node_t;
typedef struct tab_node_struct tab_node_t;

4
storage/innobase/include/rem0cmp.h

@ -141,6 +141,10 @@ cmp_rec_rec_with_match(
const ulint* offsets1,/* in: rec_get_offsets(rec1, index) */
const ulint* offsets2,/* in: rec_get_offsets(rec2, index) */
dict_index_t* index, /* in: data dictionary index */
ibool nulls_unequal,
/* in: TRUE if this is for index statistics
cardinality estimation, and innodb_stats_method
is "nulls_unequal" or "nulls_ignored" */
ulint* matched_fields, /* in/out: number of already completely
matched fields; when the function returns,
contains the value the for current

2
storage/innobase/include/rem0cmp.ic

@ -72,5 +72,5 @@ cmp_rec_rec(
ulint match_b = 0;
return(cmp_rec_rec_with_match(rec1, rec2, offsets1, offsets2, index,
&match_f, &match_b));
FALSE, &match_f, &match_b));
}

18
storage/innobase/include/srv0srv.h

@ -91,6 +91,11 @@ extern ulint srv_lock_table_size;
extern ulint srv_n_file_io_threads;
/* The "innodb_stats_method" setting, decides how InnoDB is going
to treat NULL value when collecting statistics. It is not defined
as enum type because the configure option takes unsigned integer type. */
extern ulong srv_innodb_stats_method;
#ifdef UNIV_LOG_ARCHIVE
extern ibool srv_log_archive_on;
extern ibool srv_archive_recovery;
@ -286,6 +291,19 @@ of lower numbers are included. */
#define SRV_FORCE_NO_LOG_REDO 6 /* do not do the log roll-forward
in connection with recovery */
/* Alternatives for srv_innodb_stats_method, which could be changed by
setting innodb_stats_method */
enum srv_stats_method_name_enum {
SRV_STATS_NULLS_EQUAL, /* All NULL values are treated as
equal. This is the default setting
for innodb_stats_method */
SRV_STATS_NULLS_UNEQUAL, /* All NULL values are treated as
NOT equal. */
SRV_STATS_NULLS_IGNORED /* NULL values are ignored */
};
typedef enum srv_stats_method_name_enum srv_stats_method_name_t;
/*************************************************************************
Boots Innobase server. */

3
storage/innobase/include/sync0rw.h

@ -1,7 +1,7 @@
/******************************************************
The read-write lock (for threads, not for database transactions)
(c) 1995 Innobase Oy
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
Created 9/11/1995 Heikki Tuuri
*******************************************************/
@ -409,6 +409,7 @@ Prints info of a debug struct. */
void
rw_lock_debug_print(
/*================*/
FILE* f, /* in: output stream */
rw_lock_debug_t* info); /* in: debug struct */
#endif /* UNIV_SYNC_DEBUG */

4
storage/innobase/include/trx0rseg.h

@ -121,9 +121,7 @@ struct trx_rseg_struct{
ulint id; /* rollback segment id == the index of
its slot in the trx system file copy */
mutex_t mutex; /* mutex protecting the fields in this
struct except id; NOTE that the latching
order must always be kernel mutex ->
rseg mutex */
struct except id, which is constant */
ulint space; /* space where the rollback segment is
header is placed */
ulint page_no;/* page number of the rollback segment

5
storage/innobase/include/trx0trx.h

@ -198,8 +198,9 @@ which is in the prepared state */
trx_t *
trx_get_trx_by_xid(
/*===============*/
/* out: trx or NULL */
XID* xid); /* in: X/Open XA transaction identification */
/* out: trx or NULL;
on match, the trx->xid will be invalidated */
const XID* xid); /* in: X/Open XA transaction identifier */
/**************************************************************************
If required, flushes the log to disk if we called trx_commit_for_mysql()
with trx->flush_log_later == TRUE. */

14
storage/innobase/rem/rem0cmp.c

@ -720,6 +720,10 @@ cmp_rec_rec_with_match(
const ulint* offsets1,/* in: rec_get_offsets(rec1, index) */
const ulint* offsets2,/* in: rec_get_offsets(rec2, index) */
dict_index_t* index, /* in: data dictionary index */
ibool nulls_unequal,
/* in: TRUE if this is for index statistics
cardinality estimation, and innodb_stats_method
is "nulls_unequal" or "nulls_ignored" */
ulint* matched_fields, /* in/out: number of already completely
matched fields; when the function returns,
contains the value the for current
@ -821,9 +825,13 @@ cmp_rec_rec_with_match(
|| rec2_f_len == UNIV_SQL_NULL) {
if (rec1_f_len == rec2_f_len) {
goto next_field;
/* This is limited to stats collection,
cannot use it for regular search */
if (nulls_unequal) {
ret = -1;
} else {
goto next_field;
}
} else if (rec2_f_len == UNIV_SQL_NULL) {
/* We define the SQL null to be the

10
storage/innobase/row/row0vers.c

@ -593,11 +593,15 @@ row_vers_build_for_semi_consistent_read(
mutex_enter(&kernel_mutex);
version_trx = trx_get_on_id(version_trx_id);
if (version_trx
&& (version_trx->conc_state == TRX_COMMITTED_IN_MEMORY
|| version_trx->conc_state == TRX_NOT_STARTED)) {
version_trx = NULL;
}
mutex_exit(&kernel_mutex);
if (!version_trx
|| version_trx->conc_state == TRX_NOT_STARTED
|| version_trx->conc_state == TRX_COMMITTED_IN_MEMORY) {
if (!version_trx) {
/* We found a version that belongs to a
committed transaction: return it. */

5
storage/innobase/srv/srv0srv.c

@ -218,6 +218,11 @@ ulong srv_max_buf_pool_modified_pct = 90;
/* variable counts amount of data read in total (in bytes) */
ulint srv_data_read = 0;
/* Internal setting for "innodb_stats_method". Decides how InnoDB treats
NULL value when collecting statistics. By default, it is set to
SRV_STATS_NULLS_EQUAL(0), ie. all NULL value are treated equal */
ulong srv_innodb_stats_method = SRV_STATS_NULLS_EQUAL;
/* here we count the amount of data written in total (in bytes) */
ulint srv_data_written = 0;

4
storage/innobase/sync/sync0arr.c

@ -1,7 +1,7 @@
/******************************************************
The wait array used in synchronization primitives
(c) 1995 Innobase Oy
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
Created 9/5/1995 Heikki Tuuri
*******************************************************/
@ -709,7 +709,7 @@ print:
fprintf(stderr, "rw-lock %p ",
(void*) lock);
sync_array_cell_print(stderr, cell);
rw_lock_debug_print(debug);
rw_lock_debug_print(stderr, debug);
return(TRUE);
}
}

19
storage/innobase/sync/sync0rw.c

@ -1,7 +1,7 @@
/******************************************************
The read-write lock (for thread synchronization)
(c) 1995 Innobase Oy
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
Created 9/11/1995 Heikki Tuuri
*******************************************************/
@ -830,7 +830,7 @@ rw_lock_list_print_info(
info = UT_LIST_GET_FIRST(lock->debug_list);
while (info != NULL) {
rw_lock_debug_print(info);
rw_lock_debug_print(file, info);
info = UT_LIST_GET_NEXT(list, info);
}
}
@ -870,7 +870,7 @@ rw_lock_print(
info = UT_LIST_GET_FIRST(lock->debug_list);
while (info != NULL) {
rw_lock_debug_print(info);
rw_lock_debug_print(stderr, info);
info = UT_LIST_GET_NEXT(list, info);
}
}
@ -882,28 +882,29 @@ Prints info of a debug struct. */
void
rw_lock_debug_print(
/*================*/
FILE* f, /* in: output stream */
rw_lock_debug_t* info) /* in: debug struct */
{
ulint rwt;
rwt = info->lock_type;
fprintf(stderr, "Locked: thread %lu file %s line %lu ",
fprintf(f, "Locked: thread %lu file %s line %lu ",
(ulong) os_thread_pf(info->thread_id), info->file_name,
(ulong) info->line);
if (rwt == RW_LOCK_SHARED) {
fputs("S-LOCK", stderr);
fputs("S-LOCK", f);
} else if (rwt == RW_LOCK_EX) {
fputs("X-LOCK", stderr);
fputs("X-LOCK", f);
} else if (rwt == RW_LOCK_WAIT_EX) {
fputs("WAIT X-LOCK", stderr);
fputs("WAIT X-LOCK", f);
} else {
ut_error;
}
if (info->pass != 0) {
fprintf(stderr, " pass value %lu", (ulong) info->pass);
fprintf(f, " pass value %lu", (ulong) info->pass);
}
putc('\n', stderr);
putc('\n', f);
}
/*******************************************************************

26
storage/innobase/trx/trx0trx.c

@ -2041,14 +2041,15 @@ which is in the prepared state */
trx_t*
trx_get_trx_by_xid(
/*===============*/
/* out: trx or NULL */
XID* xid) /* in: X/Open XA transaction identification */
/* out: trx or NULL;
on match, the trx->xid will be invalidated */
const XID* xid) /* in: X/Open XA transaction identifier */
{
trx_t* trx;
if (xid == NULL) {
return (NULL);
return(NULL);
}
mutex_enter(&kernel_mutex);
@ -2061,10 +2062,16 @@ trx_get_trx_by_xid(
of gtrid_lenght+bqual_length bytes should be
the same */
if (xid->gtrid_length == trx->xid.gtrid_length
if (trx->conc_state == TRX_PREPARED
&& xid->gtrid_length == trx->xid.gtrid_length
&& xid->bqual_length == trx->xid.bqual_length
&& memcmp(xid->data, trx->xid.data,
xid->gtrid_length + xid->bqual_length) == 0) {
/* Invalidate the XID, so that subsequent calls
will not find it. */
memset(&trx->xid, 0, sizeof(trx->xid));
trx->xid.formatID = -1;
break;
}
@ -2073,14 +2080,5 @@ trx_get_trx_by_xid(
mutex_exit(&kernel_mutex);
if (trx) {
if (trx->conc_state != TRX_PREPARED) {
return(NULL);
}
return(trx);
} else {
return(NULL);
}
return(trx);
}

51
storage/innodb_plugin/ChangeLog

@ -1,3 +1,54 @@
2011-01-27 The InnoDB Team
* btr/btr0cur.c:
Bug#59465 btr_estimate_number_of_different_key_vals use
incorrect offset for external_size
2011-01-27 The InnoDB Team
* include/trx0trx.h, trx/trx0trx.c:
Bug#59440 Race condition in XA ROLLBACK and XA COMMIT
after server restart
2011-01-25 The InnoDB Team
* row/row0upd.c:
Bug#59585 Fix 58912 introduces compiler warning
due to potentially uninitialized variable
2011-01-25 The InnoDB Team
* mtr/mtr0log.c:
Bug#59486 Incorrect usage of UNIV_UNLIKELY() in mlog_parse_string()
2011-01-25 The InnoDB Team
* row/row0vers.c:
Fix Bug#59464 Race condition in row_vers_build_for_semi_consistent_read
2011-01-25 The InnoDB Team
* btr/btr0btr.c, btr/btr0cur.c, btr/btr0sea.c,
buf/buf0buddy.c, buf/buf0buf.c, buf/buf0lru.c,
include/buf0buf.h, include/buf0buf.ic, include/buf0lru.h,
mem/mem0mem.c, page/page0zip.c:
Fix Bug#59707 Unused compression-related parameters
in buffer pool functions
2011-01-18 The InnoDB Team
* include/sync0rw.h, sync/sync0arr.c, sync/sync0rw.c:
Fix Bug#59579 rw_lock_debug_print outputs to stderr, not to
SHOW ENGINE INNODB STATUS
2011-01-14 The InnoDB Team
* btr/btr0cur.c, dict/dict0dict.c, handler/ha_innodb.cc,
include/btr0cur.h, include/dict0mem.h, include/rem0cmp.h,
include/rem0cmp.ic, include/srv0srv.h, rem/rem0cmp.c,
srv/srv0srv.c, innodb_bug30423.test:
Fix Bug#30423 InnoDBs treatment of NULL in index stats causes
bad "rows examined" estimates
2011-01-06 The InnoDB Team
* handler/i_s.cc, include/trx0i_s.h, trx/trx0i_s.c:
Fix Bug#55397 cannot select from innodb_trx when trx_query contains

2
storage/innodb_plugin/btr/btr0btr.c

@ -979,7 +979,7 @@ btr_page_reorganize_low(
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
#ifndef UNIV_HOTBACKUP
temp_block = buf_block_alloc(0);
temp_block = buf_block_alloc();
#else /* !UNIV_HOTBACKUP */
ut_ad(block == back_block1);
temp_block = back_block2;

165
storage/innodb_plugin/btr/btr0cur.c

@ -100,6 +100,18 @@ can be released by page reorganize, then it is reorganized */
/*--------------------------------------*/
#define BTR_BLOB_HDR_SIZE 8 /*!< Size of a BLOB
part header, in bytes */
/** Estimated table level stats from sampled value.
@param value sampled stats
@param index index being sampled
@param sample number of sampled rows
@param ext_size external stored data size
@param not_empty table not empty
@return estimated table wide stats from sampled value */
#define BTR_TABLE_STATS_FROM_SAMPLE(value, index, sample, ext_size, not_empty)\
(((value) * (ib_int64_t) index->stat_n_leaf_pages \
+ (sample) - 1 + (ext_size) + (not_empty)) / ((sample) + (ext_size)))
/* @} */
#endif /* !UNIV_HOTBACKUP */
@ -3200,10 +3212,55 @@ btr_estimate_n_rows_in_range(
}
}
/*******************************************************************//**
Record the number of non_null key values in a given index for
each n-column prefix of the index where n < dict_index_get_n_unique(index).
The estimates are eventually stored in the array:
index->stat_n_non_null_key_vals. */
static
void
btr_record_not_null_field_in_rec(
/*=============================*/
rec_t* rec, /*!< in: physical record */
ulint n_unique, /*!< in: dict_index_get_n_unique(index),
number of columns uniquely determine
an index entry */
const ulint* offsets, /*!< in: rec_get_offsets(rec, index),
its size could be for all fields or
that of "n_unique" */
ib_int64_t* n_not_null) /*!< in/out: array to record number of
not null rows for n-column prefix */
{
ulint i;
ut_ad(rec_offs_n_fields(offsets) >= n_unique);
if (n_not_null == NULL) {
return;
}
for (i = 0; i < n_unique; i++) {
ulint rec_len;
byte* field;
field = rec_get_nth_field(rec, offsets, i, &rec_len);
if (rec_len != UNIV_SQL_NULL) {
n_not_null[i]++;
} else {
/* Break if we hit the first NULL value */
break;
}
}
}
/*******************************************************************//**
Estimates the number of different key values in a given index, for
each n-column prefix of the index where n <= dict_index_get_n_unique(index).
The estimates are stored in the array index->stat_n_diff_key_vals. */
The estimates are stored in the array index->stat_n_diff_key_vals.
If innodb_stats_method is "nulls_ignored", we also record the number of
non-null values for each prefix and store the estimates in
array index->stat_n_non_null_key_vals. */
UNIV_INTERN
void
btr_estimate_number_of_different_key_vals(
@ -3217,6 +3274,8 @@ btr_estimate_number_of_different_key_vals(
ulint matched_fields;
ulint matched_bytes;
ib_int64_t* n_diff;
ib_int64_t* n_not_null;
ibool stats_null_not_equal;
ullint n_sample_pages; /* number of pages to sample */
ulint not_empty_flag = 0;
ulint total_external_size = 0;
@ -3225,16 +3284,43 @@ btr_estimate_number_of_different_key_vals(
ullint add_on;
mtr_t mtr;
mem_heap_t* heap = NULL;
ulint offsets_rec_[REC_OFFS_NORMAL_SIZE];
ulint offsets_next_rec_[REC_OFFS_NORMAL_SIZE];
ulint* offsets_rec = offsets_rec_;
ulint* offsets_next_rec= offsets_next_rec_;
rec_offs_init(offsets_rec_);
rec_offs_init(offsets_next_rec_);
ulint* offsets_rec = NULL;
ulint* offsets_next_rec = NULL;
n_cols = dict_index_get_n_unique(index);
n_diff = mem_zalloc((n_cols + 1) * sizeof(ib_int64_t));
heap = mem_heap_create((sizeof *n_diff + sizeof *n_not_null)
* (n_cols + 1)
+ dict_index_get_n_fields(index)
* (sizeof *offsets_rec
+ sizeof *offsets_next_rec));
n_diff = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
n_not_null = NULL;
/* Check srv_innodb_stats_method setting, and decide whether we
need to record non-null value and also decide if NULL is
considered equal (by setting stats_null_not_equal value) */
switch (srv_innodb_stats_method) {
case SRV_STATS_NULLS_IGNORED:
n_not_null = mem_heap_zalloc(heap, (n_cols + 1)
* sizeof *n_not_null);
/* fall through */
case SRV_STATS_NULLS_UNEQUAL:
/* for both SRV_STATS_NULLS_IGNORED and SRV_STATS_NULLS_UNEQUAL
case, we will treat NULLs as unequal value */
stats_null_not_equal = TRUE;
break;
case SRV_STATS_NULLS_EQUAL:
stats_null_not_equal = FALSE;
break;
default:
ut_error;
}
/* It makes no sense to test more pages than are contained
in the index, thus we lower the number if it is too high */
@ -3251,7 +3337,6 @@ btr_estimate_number_of_different_key_vals(
/* We sample some pages in the index to get an estimate */
for (i = 0; i < n_sample_pages; i++) {
rec_t* supremum;
mtr_start(&mtr);
btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr);
@ -3264,18 +3349,25 @@ btr_estimate_number_of_different_key_vals(
page = btr_cur_get_page(&cursor);
supremum = page_get_supremum_rec(page);
rec = page_rec_get_next(page_get_infimum_rec(page));
if (rec != supremum) {
if (!page_rec_is_supremum(rec)) {
not_empty_flag = 1;
offsets_rec = rec_get_offsets(rec, index, offsets_rec,
ULINT_UNDEFINED, &heap);
if (n_not_null) {
btr_record_not_null_field_in_rec(
rec, n_cols, offsets_rec, n_not_null);
}
}
while (rec != supremum) {
while (!page_rec_is_supremum(rec)) {
rec_t* next_rec = page_rec_get_next(rec);
if (next_rec == supremum) {
if (page_rec_is_supremum(next_rec)) {
total_external_size +=
btr_rec_get_externally_stored_len(
rec, offsets_rec);
break;
}
@ -3283,11 +3375,13 @@ btr_estimate_number_of_different_key_vals(
matched_bytes = 0;
offsets_next_rec = rec_get_offsets(next_rec, index,
offsets_next_rec,
n_cols, &heap);
ULINT_UNDEFINED,
&heap);
cmp_rec_rec_with_match(rec, next_rec,
offsets_rec, offsets_next_rec,
index, &matched_fields,
index, stats_null_not_equal,
&matched_fields,
&matched_bytes);
for (j = matched_fields + 1; j <= n_cols; j++) {
@ -3297,6 +3391,12 @@ btr_estimate_number_of_different_key_vals(
n_diff[j]++;
}
if (n_not_null) {
btr_record_not_null_field_in_rec(
next_rec, n_cols, offsets_next_rec,
n_not_null);
}
total_external_size
+= btr_rec_get_externally_stored_len(
rec, offsets_rec);
@ -3331,10 +3431,6 @@ btr_estimate_number_of_different_key_vals(
}
}
offsets_rec = rec_get_offsets(rec, index, offsets_rec,
ULINT_UNDEFINED, &heap);
total_external_size += btr_rec_get_externally_stored_len(
rec, offsets_rec);
mtr_commit(&mtr);
}
@ -3348,13 +3444,9 @@ btr_estimate_number_of_different_key_vals(
for (j = 0; j <= n_cols; j++) {
index->stat_n_diff_key_vals[j]
= ((n_diff[j]
* (ib_int64_t)index->stat_n_leaf_pages
+ n_sample_pages - 1
+ total_external_size
+ not_empty_flag)
/ (n_sample_pages
+ total_external_size));
= BTR_TABLE_STATS_FROM_SAMPLE(
n_diff[j], index, n_sample_pages,
total_external_size, not_empty_flag);
/* If the tree is small, smaller than
10 * n_sample_pages + total_external_size, then
@ -3373,12 +3465,20 @@ btr_estimate_number_of_different_key_vals(
}
index->stat_n_diff_key_vals[j] += add_on;
}
mem_free(n_diff);
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
/* Update the stat_n_non_null_key_vals[] with our
sampled result. stat_n_non_null_key_vals[] is created
and initialized to zero in dict_index_add_to_cache(),
along with stat_n_diff_key_vals[] array */
if (n_not_null != NULL && (j < n_cols)) {
index->stat_n_non_null_key_vals[j] =
BTR_TABLE_STATS_FROM_SAMPLE(
n_not_null[j], index, n_sample_pages,
total_external_size, not_empty_flag);
}
}
mem_heap_free(heap);
}
/*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/
@ -3667,13 +3767,12 @@ btr_blob_free(
&& buf_block_get_space(block) == space
&& buf_block_get_page_no(block) == page_no) {
if (buf_LRU_free_block(&block->page, all, NULL)
!= BUF_LRU_FREED
if (buf_LRU_free_block(&block->page, all) != BUF_LRU_FREED
&& all && block->page.zip.data) {
/* Attempt to deallocate the uncompressed page
if the whole block cannot be deallocted. */
buf_LRU_free_block(&block->page, FALSE, NULL);
buf_LRU_free_block(&block->page, FALSE);
}
}

2
storage/innodb_plugin/btr/btr0sea.c

@ -141,7 +141,7 @@ btr_search_check_free_space_in_heap(void)
be enough free space in the hash table. */
if (heap->free_block == NULL) {
buf_block_t* block = buf_block_alloc(0);
buf_block_t* block = buf_block_alloc();
rw_lock_x_lock(&btr_search_latch);

2
storage/innodb_plugin/buf/buf0buddy.c

@ -327,7 +327,7 @@ buf_buddy_alloc_low(
/* Try replacing an uncompressed page in the buffer pool. */
buf_pool_mutex_exit();
block = buf_LRU_get_free_block(0);
block = buf_LRU_get_free_block();
*lru = TRUE;
buf_pool_mutex_enter();

14
storage/innodb_plugin/buf/buf0buf.c

@ -1283,7 +1283,7 @@ shrink_again:
buf_LRU_make_block_old(&block->page);
dirty++;
} else if (buf_LRU_free_block(&block->page, TRUE, NULL)
} else if (buf_LRU_free_block(&block->page, TRUE)
!= BUF_LRU_FREED) {
nonfree++;
}
@ -1729,8 +1729,7 @@ err_exit:
mutex_enter(block_mutex);
/* Discard the uncompressed page frame if possible. */
if (buf_LRU_free_block(bpage, FALSE, NULL)
== BUF_LRU_FREED) {
if (buf_LRU_free_block(bpage, FALSE) == BUF_LRU_FREED) {
mutex_exit(block_mutex);
goto lookup;
@ -2165,7 +2164,7 @@ wait_until_unfixed:
buf_pool_mutex_exit();
mutex_exit(&buf_pool_zip_mutex);
block = buf_LRU_get_free_block(0);
block = buf_LRU_get_free_block();
ut_a(block);
buf_pool_mutex_enter();
@ -2291,8 +2290,7 @@ wait_until_unfixed:
/* Try to evict the block from the buffer pool, to use the
insert buffer as much as possible. */
if (buf_LRU_free_block(&block->page, TRUE, NULL)
== BUF_LRU_FREED) {
if (buf_LRU_free_block(&block->page, TRUE) == BUF_LRU_FREED) {
buf_pool_mutex_exit();
mutex_exit(&block->mutex);
fprintf(stderr,
@ -2829,7 +2827,7 @@ buf_page_init_for_read(
&& UNIV_LIKELY(!recv_recovery_is_on())) {
block = NULL;
} else {
block = buf_LRU_get_free_block(0);
block = buf_LRU_get_free_block();
ut_ad(block);
}
@ -3001,7 +2999,7 @@ buf_page_create(
ut_ad(mtr->state == MTR_ACTIVE);
ut_ad(space || !zip_size);
free_block = buf_LRU_get_free_block(0);
free_block = buf_LRU_get_free_block();
buf_pool_mutex_enter();

44
storage/innodb_plugin/buf/buf0lru.c

@ -575,7 +575,7 @@ buf_LRU_free_from_unzip_LRU_list(
ut_ad(block->page.in_LRU_list);
mutex_enter(&block->mutex);
freed = buf_LRU_free_block(&block->page, FALSE, NULL);
freed = buf_LRU_free_block(&block->page, FALSE);
mutex_exit(&block->mutex);
switch (freed) {
@ -636,7 +636,7 @@ buf_LRU_free_from_common_LRU_list(
mutex_enter(block_mutex);
accessed = buf_page_is_accessed(bpage);
freed = buf_LRU_free_block(bpage, TRUE, NULL);
freed = buf_LRU_free_block(bpage, TRUE);
mutex_exit(block_mutex);
switch (freed) {
@ -798,10 +798,8 @@ LRU list to the free list.
@return the free control block, in state BUF_BLOCK_READY_FOR_USE */
UNIV_INTERN
buf_block_t*
buf_LRU_get_free_block(
/*===================*/
ulint zip_size) /*!< in: compressed page size in bytes,
or 0 if uncompressed tablespace */
buf_LRU_get_free_block(void)
/*========================*/
{
buf_block_t* block = NULL;
ibool freed;
@ -877,26 +875,10 @@ loop:
/* If there is a block in the free list, take it */
block = buf_LRU_get_free_only();
if (block) {
#ifdef UNIV_DEBUG
block->page.zip.m_start =
#endif /* UNIV_DEBUG */
block->page.zip.m_end =
block->page.zip.m_nonempty =
block->page.zip.n_blobs = 0;
if (UNIV_UNLIKELY(zip_size)) {
ibool lru;
page_zip_set_size(&block->page.zip, zip_size);
block->page.zip.data = buf_buddy_alloc(zip_size, &lru);
UNIV_MEM_DESC(block->page.zip.data, zip_size, block);
} else {
page_zip_set_size(&block->page.zip, 0);
block->page.zip.data = NULL;
}
buf_pool_mutex_exit();
buf_pool_mutex_exit();
if (block) {
memset(&block->page.zip, 0, sizeof block->page.zip);
if (started_monitor) {
srv_print_innodb_monitor = mon_value_was;
@ -908,8 +890,6 @@ loop:
/* If no block was in the free list, search from the end of the LRU
list and try to free a block there */
buf_pool_mutex_exit();
freed = buf_LRU_search_and_free_block(n_iterations);
if (freed > 0) {
@ -1378,12 +1358,8 @@ enum buf_lru_free_block_status
buf_LRU_free_block(
/*===============*/
buf_page_t* bpage, /*!< in: block to be freed */
ibool zip, /*!< in: TRUE if should remove also the
ibool zip) /*!< in: TRUE if should remove also the
compressed page of an uncompressed page */
ibool* buf_pool_mutex_released)
/*!< in: pointer to a variable that will
be assigned TRUE if buf_pool_mutex
was temporarily released, or NULL */
{
buf_page_t* b = NULL;
mutex_t* block_mutex = buf_page_get_mutex(bpage);
@ -1554,10 +1530,6 @@ alloc:
b->io_fix = BUF_IO_READ;
}
if (buf_pool_mutex_released) {
*buf_pool_mutex_released = TRUE;
}
buf_pool_mutex_exit();
mutex_exit(block_mutex);

10
storage/innodb_plugin/dict/dict0dict.c

@ -1669,6 +1669,12 @@ undo_size_ok:
new_index->heap,
(1 + dict_index_get_n_unique(new_index))
* sizeof(ib_int64_t));
new_index->stat_n_non_null_key_vals = mem_heap_zalloc(
new_index->heap,
(1 + dict_index_get_n_unique(new_index))
* sizeof(*new_index->stat_n_non_null_key_vals));
/* Give some sensible values to stat_n_... in case we do
not calculate statistics quickly enough */
@ -4291,6 +4297,10 @@ dict_update_statistics(
for (i = dict_index_get_n_unique(index); i; ) {
index->stat_n_diff_key_vals[i--] = 1;
}
memset(index->stat_n_non_null_key_vals, 0,
(1 + dict_index_get_n_unique(index))
* sizeof(*index->stat_n_non_null_key_vals));
}
index = dict_table_get_next_index(index);

95
storage/innodb_plugin/handler/ha_innodb.cc

@ -174,6 +174,25 @@ static char* internal_innobase_data_file_path = NULL;
static char* innodb_version_str = (char*) INNODB_VERSION_STR;
/** Possible values for system variable "innodb_stats_method". The values
are defined the same as its corresponding MyISAM system variable
"myisam_stats_method"(see "myisam_stats_method_names"), for better usability */
static const char* innodb_stats_method_names[] = {
"nulls_equal",
"nulls_unequal",
"nulls_ignored",
NullS
};
/** Used to define an enumerate type of the system variable innodb_stats_method.
This is the same as "myisam_stats_method_typelib" */
static TYPELIB innodb_stats_method_typelib = {
array_elements(innodb_stats_method_names) - 1,
"innodb_stats_method_typelib",
innodb_stats_method_names,
NULL
};
/* The following counter is used to convey information to InnoDB
about server activity: in selects it is not sensible to call
srv_active_wake_master_thread after each fetch or search, we only do
@ -7507,6 +7526,65 @@ innobase_get_mysql_key_number_for_index(
return(0);
}
/*********************************************************************//**
Calculate Record Per Key value. Need to exclude the NULL value if
innodb_stats_method is set to "nulls_ignored"
@return estimated record per key value */
static
ha_rows
innodb_rec_per_key(
/*===============*/
dict_index_t* index, /*!< in: dict_index_t structure */
ulint i, /*!< in: the column we are
calculating rec per key */
ha_rows records) /*!< in: estimated total records */
{
ha_rows rec_per_key;
ut_ad(i < dict_index_get_n_unique(index));
/* Note the stat_n_diff_key_vals[] stores the diff value with
n-prefix indexing, so it is always stat_n_diff_key_vals[i + 1] */
if (index->stat_n_diff_key_vals[i + 1] == 0) {
rec_per_key = records;
} else if (srv_innodb_stats_method == SRV_STATS_NULLS_IGNORED) {
ib_int64_t num_null;
/* Number of rows with NULL value in this
field */
num_null = records - index->stat_n_non_null_key_vals[i];
/* In theory, index->stat_n_non_null_key_vals[i]
should always be less than the number of records.
Since this is statistics value, the value could
have slight discrepancy. But we will make sure
the number of null values is not a negative number. */
num_null = (num_null < 0) ? 0 : num_null;
/* If the number of NULL values is the same as or
large than that of the distinct values, we could
consider that the table consists mostly of NULL value.
Set rec_per_key to 1. */
if (index->stat_n_diff_key_vals[i + 1] <= num_null) {
rec_per_key = 1;
} else {
/* Need to exclude rows with NULL values from
rec_per_key calculation */
rec_per_key = (ha_rows)(
(records - num_null)
/ (index->stat_n_diff_key_vals[i + 1]
- num_null));
}
} else {
rec_per_key = (ha_rows)
(records / index->stat_n_diff_key_vals[i + 1]);
}
return(rec_per_key);
}
/*********************************************************************//**
Returns statistics information of the table to the MySQL interpreter,
in various fields of the handle object. */
@ -7737,13 +7815,8 @@ ha_innobase::info_low(
break;
}
if (index->stat_n_diff_key_vals[j + 1] == 0) {
rec_per_key = stats.records;
} else {
rec_per_key = (ha_rows)(stats.records /
index->stat_n_diff_key_vals[j + 1]);
}
rec_per_key = innodb_rec_per_key(
index, j, stats.records);
/* Since MySQL seems to favor table scans
too much over index searches, we pretend
@ -10934,6 +11007,13 @@ static MYSQL_SYSVAR_STR(change_buffering, innobase_change_buffering,
innodb_change_buffering_validate,
innodb_change_buffering_update, "inserts");
static MYSQL_SYSVAR_ENUM(stats_method, srv_innodb_stats_method,
PLUGIN_VAR_RQCMDARG,
"Specifies how InnoDB index statistics collection code should "
"treat NULLs. Possible values are NULLS_EQUAL (default), "
"NULLS_UNEQUAL and NULLS_IGNORED",
NULL, NULL, SRV_STATS_NULLS_EQUAL, &innodb_stats_method_typelib);
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
static MYSQL_SYSVAR_UINT(change_buffering_debug, ibuf_debug,
PLUGIN_VAR_RQCMDARG,
@ -10988,6 +11068,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(stats_on_metadata),
MYSQL_SYSVAR(stats_sample_pages),
MYSQL_SYSVAR(adaptive_hash_index),
MYSQL_SYSVAR(stats_method),
MYSQL_SYSVAR(replication_delay),
MYSQL_SYSVAR(status_file),
MYSQL_SYSVAR(strict_mode),

5
storage/innodb_plugin/include/btr0cur.h

@ -478,7 +478,10 @@ btr_estimate_n_rows_in_range(
/*******************************************************************//**
Estimates the number of different key values in a given index, for
each n-column prefix of the index where n <= dict_index_get_n_unique(index).
The estimates are stored in the array index->stat_n_diff_key_vals. */
The estimates are stored in the array index->stat_n_diff_key_vals.
If innodb_stats_method is nulls_ignored, we also record the number of
non-null values for each prefix and stored the estimates in
array index->stat_n_non_null_key_vals. */
UNIV_INTERN
void
btr_estimate_number_of_different_key_vals(

6
storage/innodb_plugin/include/buf0buf.h

@ -165,10 +165,8 @@ Allocates a buffer block.
@return own: the allocated block, in state BUF_BLOCK_MEMORY */
UNIV_INLINE
buf_block_t*
buf_block_alloc(
/*============*/
ulint zip_size); /*!< in: compressed page size in bytes,
or 0 if uncompressed tablespace */
buf_block_alloc(void);
/*=================*/
/********************************************************************//**
Frees a buffer block which does not contain a file page. */
UNIV_INLINE

8
storage/innodb_plugin/include/buf0buf.ic

@ -719,14 +719,12 @@ Allocates a buffer block.
@return own: the allocated block, in state BUF_BLOCK_MEMORY */
UNIV_INLINE
buf_block_t*
buf_block_alloc(
/*============*/
ulint zip_size) /*!< in: compressed page size in bytes,
or 0 if uncompressed tablespace */
buf_block_alloc(void)
/*=================*/
{
buf_block_t* block;
block = buf_LRU_get_free_block(zip_size);
block = buf_LRU_get_free_block();
buf_block_set_state(block, BUF_BLOCK_MEMORY);

14
storage/innodb_plugin/include/buf0lru.h

@ -110,12 +110,9 @@ enum buf_lru_free_block_status
buf_LRU_free_block(
/*===============*/
buf_page_t* bpage, /*!< in: block to be freed */
ibool zip, /*!< in: TRUE if should remove also the
ibool zip) /*!< in: TRUE if should remove also the
compressed page of an uncompressed page */
ibool* buf_pool_mutex_released);
/*!< in: pointer to a variable that will
be assigned TRUE if buf_pool_mutex
was temporarily released, or NULL */
__attribute__((nonnull));
/******************************************************************//**
Try to free a replaceable block.
@return TRUE if found and freed */
@ -146,10 +143,9 @@ LRU list to the free list.
@return the free control block, in state BUF_BLOCK_READY_FOR_USE */
UNIV_INTERN
buf_block_t*
buf_LRU_get_free_block(
/*===================*/
ulint zip_size); /*!< in: compressed page size in bytes,
or 0 if uncompressed tablespace */
buf_LRU_get_free_block(void)
/*========================*/
__attribute__((warn_unused_result));
/******************************************************************//**
Puts a block back to the free list. */

6
storage/innodb_plugin/include/dict0mem.h

@ -321,6 +321,12 @@ struct dict_index_struct{
dict_get_n_unique(index); we
periodically calculate new
estimates */
ib_int64_t* stat_n_non_null_key_vals;
/* approximate number of non-null key values
for this index, for each column where
n < dict_get_n_unique(index); This
is used when innodb_stats_method is
"nulls_ignored". */
ulint stat_index_size;
/*!< approximate index size in
database pages */

5
storage/innodb_plugin/include/dict0types.h

@ -33,11 +33,6 @@ typedef struct dict_index_struct dict_index_t;
typedef struct dict_table_struct dict_table_t;
typedef struct dict_foreign_struct dict_foreign_t;
/* A cluster object is a table object with the type field set to
DICT_CLUSTERED */
typedef dict_table_t dict_cluster_t;
typedef struct ind_node_struct ind_node_t;
typedef struct tab_node_struct tab_node_t;

4
storage/innodb_plugin/include/rem0cmp.h

@ -165,6 +165,10 @@ cmp_rec_rec_with_match(
const ulint* offsets1,/*!< in: rec_get_offsets(rec1, index) */
const ulint* offsets2,/*!< in: rec_get_offsets(rec2, index) */
dict_index_t* index, /*!< in: data dictionary index */
ibool nulls_unequal,
/* in: TRUE if this is for index statistics
cardinality estimation, and innodb_stats_method
is "nulls_unequal" or "nulls_ignored" */
ulint* matched_fields, /*!< in/out: number of already completely
matched fields; when the function returns,
contains the value the for current

2
storage/innodb_plugin/include/rem0cmp.ic

@ -87,5 +87,5 @@ cmp_rec_rec(
ulint match_b = 0;
return(cmp_rec_rec_with_match(rec1, rec2, offsets1, offsets2, index,
&match_f, &match_b));
FALSE, &match_f, &match_b));
}

18
storage/innodb_plugin/include/srv0srv.h

@ -154,6 +154,11 @@ capacity. PCT_IO(5) -> returns the number of IO operations that
is 5% of the max where max is srv_io_capacity. */
#define PCT_IO(p) ((ulong) (srv_io_capacity * ((double) p / 100.0)))
/* The "innodb_stats_method" setting, decides how InnoDB is going
to treat NULL value when collecting statistics. It is not defined
as enum type because the configure option takes unsigned integer type. */
extern ulong srv_innodb_stats_method;
#ifdef UNIV_LOG_ARCHIVE
extern ibool srv_log_archive_on;
extern ibool srv_archive_recovery;
@ -363,6 +368,19 @@ enum {
in connection with recovery */
};
/* Alternatives for srv_innodb_stats_method, which could be changed by
setting innodb_stats_method */
enum srv_stats_method_name_enum {
SRV_STATS_NULLS_EQUAL, /* All NULL values are treated as
equal. This is the default setting
for innodb_stats_method */
SRV_STATS_NULLS_UNEQUAL, /* All NULL values are treated as
NOT equal. */
SRV_STATS_NULLS_IGNORED /* NULL values are ignored */
};
typedef enum srv_stats_method_name_enum srv_stats_method_name_t;
#ifndef UNIV_HOTBACKUP
/** Types of threads existing in the system. */
enum srv_thread_type {

3
storage/innodb_plugin/include/sync0rw.h

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@ -490,6 +490,7 @@ UNIV_INTERN
void
rw_lock_debug_print(
/*================*/
FILE* f, /*!< in: output stream */
rw_lock_debug_t* info); /*!< in: debug struct */
#endif /* UNIV_SYNC_DEBUG */

4
storage/innodb_plugin/include/trx0rseg.h

@ -135,9 +135,7 @@ struct trx_rseg_struct{
ulint id; /*!< rollback segment id == the index of
its slot in the trx system file copy */
mutex_t mutex; /*!< mutex protecting the fields in this
struct except id; NOTE that the latching
order must always be kernel mutex ->
rseg mutex */
struct except id, which is constant */
ulint space; /*!< space where the rollback segment is
header is placed */
ulint zip_size;/* compressed page size of space

4
storage/innodb_plugin/include/trx0trx.h

@ -214,12 +214,12 @@ trx_recover_for_mysql(
/*******************************************************************//**
This function is used to find one X/Open XA distributed transaction
which is in the prepared state
@return trx or NULL */
@return trx or NULL; on match, the trx->xid will be invalidated */
UNIV_INTERN
trx_t *
trx_get_trx_by_xid(
/*===============*/
XID* xid); /*!< in: X/Open XA transaction identification */
const XID* xid); /*!< in: X/Open XA transaction identifier */
/**********************************************************************//**
If required, flushes the log to disk if we called trx_commit_for_mysql()
with trx->flush_log_later == TRUE.

2
storage/innodb_plugin/include/univ.i

@ -412,7 +412,7 @@ it is read or written. */
/* Use sun_prefetch when compile with Sun Studio */
# define UNIV_EXPECT(expr,value) (expr)
# define UNIV_LIKELY_NULL(expr) (expr)
# define UNIV_PREFETCH_R(addr) sun_prefetch_read_many(addr)
# define UNIV_PREFETCH_R(addr) sun_prefetch_read_many((void*) addr)
# define UNIV_PREFETCH_RW(addr) sun_prefetch_write_many(addr)
#else
/* Dummy versions of the macros */

2
storage/innodb_plugin/mem/mem0mem.c

@ -347,7 +347,7 @@ mem_heap_create_block(
return(NULL);
}
} else {
buf_block = buf_block_alloc(0);
buf_block = buf_block_alloc();
}
block = (mem_block_t*) buf_block->frame;

2
storage/innodb_plugin/mtr/mtr0log.c

@ -408,7 +408,7 @@ mlog_parse_string(
ptr += 2;
if (UNIV_UNLIKELY(offset >= UNIV_PAGE_SIZE)
|| UNIV_UNLIKELY(len + offset) > UNIV_PAGE_SIZE) {
|| UNIV_UNLIKELY(len + offset > UNIV_PAGE_SIZE)) {
recv_sys->found_corrupt_log = TRUE;
return(NULL);

2
storage/innodb_plugin/page/page0zip.c

@ -4439,7 +4439,7 @@ page_zip_reorganize(
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
#ifndef UNIV_HOTBACKUP
temp_block = buf_block_alloc(0);
temp_block = buf_block_alloc();
btr_search_drop_page_hash_index(block);
block->check_index_page_at_flush = TRUE;
#else /* !UNIV_HOTBACKUP */

14
storage/innodb_plugin/rem/rem0cmp.c

@ -862,6 +862,10 @@ cmp_rec_rec_with_match(
const ulint* offsets1,/*!< in: rec_get_offsets(rec1, index) */
const ulint* offsets2,/*!< in: rec_get_offsets(rec2, index) */
dict_index_t* index, /*!< in: data dictionary index */
ibool nulls_unequal,
/* in: TRUE if this is for index statistics
cardinality estimation, and innodb_stats_method
is "nulls_unequal" or "nulls_ignored" */
ulint* matched_fields, /*!< in/out: number of already completely
matched fields; when the function returns,
contains the value the for current
@ -961,9 +965,13 @@ cmp_rec_rec_with_match(
|| rec2_f_len == UNIV_SQL_NULL) {
if (rec1_f_len == rec2_f_len) {
goto next_field;
/* This is limited to stats collection,
cannot use it for regular search */
if (nulls_unequal) {
ret = -1;
} else {
goto next_field;
}
} else if (rec2_f_len == UNIV_SQL_NULL) {
/* We define the SQL null to be the

4
storage/innodb_plugin/row/row0upd.c

@ -1252,6 +1252,10 @@ row_upd_changes_ord_field_binary(
|| dfield_is_null(dfield)) {
/* do nothing special */
} else if (UNIV_LIKELY_NULL(ext)) {
/* Silence a compiler warning without
silencing a Valgrind error. */
dfield_len = 0;
UNIV_MEM_INVALID(&dfield_len, sizeof dfield_len);
/* See if the column is stored externally. */
buf = row_ext_lookup(ext, col_no, &dfield_len);

10
storage/innodb_plugin/row/row0vers.c

@ -669,11 +669,15 @@ row_vers_build_for_semi_consistent_read(
mutex_enter(&kernel_mutex);
version_trx = trx_get_on_id(version_trx_id);
if (version_trx
&& (version_trx->conc_state == TRX_COMMITTED_IN_MEMORY
|| version_trx->conc_state == TRX_NOT_STARTED)) {
version_trx = NULL;
}
mutex_exit(&kernel_mutex);
if (!version_trx
|| version_trx->conc_state == TRX_NOT_STARTED
|| version_trx->conc_state == TRX_COMMITTED_IN_MEMORY) {
if (!version_trx) {
/* We found a version that belongs to a
committed transaction: return it. */

5
storage/innodb_plugin/srv/srv0srv.c

@ -243,6 +243,11 @@ UNIV_INTERN ulong srv_max_buf_pool_modified_pct = 75;
/* variable counts amount of data read in total (in bytes) */
UNIV_INTERN ulint srv_data_read = 0;
/* Internal setting for "innodb_stats_method". Decides how InnoDB treats
NULL value when collecting statistics. By default, it is set to
SRV_STATS_NULLS_EQUAL(0), ie. all NULL value are treated equal */
ulong srv_innodb_stats_method = SRV_STATS_NULLS_EQUAL;
/* here we count the amount of data written in total (in bytes) */
UNIV_INTERN ulint srv_data_written = 0;

4
storage/innodb_plugin/sync/sync0arr.c

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@ -715,7 +715,7 @@ print:
fprintf(stderr, "rw-lock %p ",
(void*) lock);
sync_array_cell_print(stderr, cell);
rw_lock_debug_print(debug);
rw_lock_debug_print(stderr, debug);
return(TRUE);
}
}

19
storage/innodb_plugin/sync/sync0rw.c

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@ -925,7 +925,7 @@ rw_lock_list_print_info(
info = UT_LIST_GET_FIRST(lock->debug_list);
while (info != NULL) {
rw_lock_debug_print(info);
rw_lock_debug_print(file, info);
info = UT_LIST_GET_NEXT(list, info);
}
}
@ -973,7 +973,7 @@ rw_lock_print(
info = UT_LIST_GET_FIRST(lock->debug_list);
while (info != NULL) {
rw_lock_debug_print(info);
rw_lock_debug_print(stderr, info);
info = UT_LIST_GET_NEXT(list, info);
}
}
@ -985,28 +985,29 @@ UNIV_INTERN
void
rw_lock_debug_print(
/*================*/
FILE* f, /*!< in: output stream */
rw_lock_debug_t* info) /*!< in: debug struct */
{
ulint rwt;
rwt = info->lock_type;
fprintf(stderr, "Locked: thread %lu file %s line %lu ",
fprintf(f, "Locked: thread %lu file %s line %lu ",
(ulong) os_thread_pf(info->thread_id), info->file_name,
(ulong) info->line);
if (rwt == RW_LOCK_SHARED) {
fputs("S-LOCK", stderr);
fputs("S-LOCK", f);
} else if (rwt == RW_LOCK_EX) {
fputs("X-LOCK", stderr);
fputs("X-LOCK", f);
} else if (rwt == RW_LOCK_WAIT_EX) {
fputs("WAIT X-LOCK", stderr);
fputs("WAIT X-LOCK", f);
} else {
ut_error;
}
if (info->pass != 0) {
fprintf(stderr, " pass value %lu", (ulong) info->pass);
fprintf(f, " pass value %lu", (ulong) info->pass);
}
putc('\n', stderr);
putc('\n', f);
}
/***************************************************************//**

25
storage/innodb_plugin/trx/trx0trx.c

@ -2010,18 +2010,18 @@ trx_recover_for_mysql(
/*******************************************************************//**
This function is used to find one X/Open XA distributed transaction
which is in the prepared state
@return trx or NULL */
@return trx or NULL; on match, the trx->xid will be invalidated */
UNIV_INTERN
trx_t*
trx_get_trx_by_xid(
/*===============*/
XID* xid) /*!< in: X/Open XA transaction identification */
const XID* xid) /*!< in: X/Open XA transaction identifier */
{
trx_t* trx;
if (xid == NULL) {
return (NULL);
return(NULL);
}
mutex_enter(&kernel_mutex);
@ -2034,10 +2034,16 @@ trx_get_trx_by_xid(
of gtrid_lenght+bqual_length bytes should be
the same */
if (xid->gtrid_length == trx->xid.gtrid_length
if (trx->conc_state == TRX_PREPARED
&& xid->gtrid_length == trx->xid.gtrid_length
&& xid->bqual_length == trx->xid.bqual_length
&& memcmp(xid->data, trx->xid.data,
xid->gtrid_length + xid->bqual_length) == 0) {
/* Invalidate the XID, so that subsequent calls
will not find it. */
memset(&trx->xid, 0, sizeof(trx->xid));
trx->xid.formatID = -1;
break;
}
@ -2046,14 +2052,5 @@ trx_get_trx_by_xid(
mutex_exit(&kernel_mutex);
if (trx) {
if (trx->conc_state != TRX_PREPARED) {
return(NULL);
}
return(trx);
} else {
return(NULL);
}
return(trx);
}
Loading…
Cancel
Save