merge from 5.1 main

This commit is contained in:
Bjorn Munch 2011-02-04 12:37:01 +01:00
commit bb3e48c29a
92 changed files with 1947 additions and 378 deletions

View File

@ -1884,6 +1884,15 @@ dnl
MYSQL_CHECK_TIME_T
dnl
dnl check size of time_t
dnl
AC_CHECK_SIZEOF(time_t, 8)
if test "$ac_cv_sizeof_time_t" -eq 0
then
AC_MSG_ERROR("MySQL needs a time_t type.")
fi
# do we need #pragma interface/#pragma implementation ?
# yes if it's gcc 2.x, and not icc pretending to be gcc, and not cygwin

View File

@ -169,6 +169,11 @@ typedef uint rf_SetTimer;
#define SIZEOF_LONG 4
#define SIZEOF_LONG_LONG 8
#define SIZEOF_OFF_T 8
/*
The size of time_t depends on the compiler.
But it's 8 for all the supported VC versions.
*/
#define SIZEOF_TIME_T 8
#ifdef _WIN64
#define SIZEOF_CHARP 8
#else

View File

@ -52,6 +52,19 @@ typedef long my_time_t;
/* two-digit years < this are 20..; >= this are 19.. */
#define YY_PART_YEAR 70
/*
check for valid times only if the range of time_t is greater than
the range of my_time_t
*/
#if SIZEOF_TIME_T > 4 || defined(TIME_T_UNSIGNED)
# define IS_TIME_T_VALID_FOR_TIMESTAMP(x) \
((x) <= TIMESTAMP_MAX_VALUE && \
(x) >= TIMESTAMP_MIN_VALUE)
#else
# define IS_TIME_T_VALID_FOR_TIMESTAMP(x) \
((x) >= TIMESTAMP_MIN_VALUE)
#endif
/* Flags to str_to_datetime */
#define TIME_FUZZY_DATE 1
#define TIME_DATETIME_ONLY 2

View File

@ -0,0 +1,64 @@
# BUG#59338 Inconsistency in binlog for statements that don't change any rows STATEMENT SBR
# In SBR, if a statement does not fail, it is always written to the binary log,
# regardless if rows are changed or not. If there is a failure, a statement is
# only written to the binary log if a non-transactional (.e.g. MyIsam) engine
# is updated. INSERT ON DUPLICATE KEY UPDATE was not following the rule above
# and was not written to the binary log, if then engine was Innodb.
#
# In this test case, we check if INSERT ON DUPLICATE KEY UPDATE that does not
# change anything is still written to the binary log.
# Prepare environment
--connection master
eval CREATE TABLE t1 (
a INT UNSIGNED NOT NULL PRIMARY KEY
) ENGINE=$engine_type;
eval CREATE TABLE t2 (
a INT UNSIGNED
) ENGINE=$engine_type;
INSERT INTO t1 VALUES (1);
INSERT INTO t2 VALUES (1);
# An insert duplicate that does not update anything must be written to the binary
# log in SBR and MIXED modes. We check this property by summing a before and after
# the update and comparing the binlog positions. The sum should be the same at both
# points and the statement should be in the binary log.
--let $binlog_file= query_get_value("SHOW MASTER STATUS", File, 1)
--let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1)
--let $statement_file=INSERT INTO t1 SELECT t2.a FROM t2 ORDER BY t2.a ON DUPLICATE KEY UPDATE t1.a= t1.a
--eval $statement_file
--let $assert_cond= SUM(a) = 1 FROM t1
--let $assert_text= Sum of elements in t1 should be 1.
--source include/assert.inc
if (`SELECT @@BINLOG_FORMAT = 'ROW'`)
{
--let $binlog_position_cmp= =
--let $assert_cond= [SHOW MASTER STATUS, Position, 1] $binlog_position_cmp $binlog_start
--let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.
}
if (`SELECT @@BINLOG_FORMAT != 'ROW' && UPPER('$engine_type') = UPPER('Innodb')`)
{
--let $assert_cond= \'[\'SHOW BINLOG EVENTS IN "$binlog_file" FROM $binlog_start LIMIT 1, 1\', Info, 1]\' LIKE \'%$statement_file\'
--let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.
}
if (`SELECT @@BINLOG_FORMAT != 'ROW' && UPPER('$engine_type') = UPPER('MyIsam')`)
{
--let $assert_cond= \'[\'SHOW BINLOG EVENTS IN "$binlog_file" FROM $binlog_start LIMIT 0, 1\', Info, 1]\' LIKE \'%$statement_file\'
--let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.
}
--source include/assert.inc
# Compare master and slave
--sync_slave_with_master
--let $diff_tables= master:test.t1 , slave:test.t1
--source include/diff_tables.inc
# Clean up
--connection master
drop table t1, t2;
--sync_slave_with_master

View File

@ -5,6 +5,7 @@
# Slave needs to be started with --innodb to store table in InnoDB.
# Same test for MyISAM (which had no bug).
--connection master
eval CREATE TABLE t1 (
a int unsigned not null auto_increment primary key,
b int unsigned,
@ -32,38 +33,49 @@ INSERT INTO t2 VALUES (5, 4);
INSERT INTO t2 VALUES (6, 6);
INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a;
--let $assert_cond= COUNT(*) = 6 FROM t1
--let $assert_text= Count of elements in t1 should be 6.
--source include/assert.inc
# Compare results
# Compare master and slave
--sync_slave_with_master
--let $diff_tables= master:test.t1 , slave:test.t1
--source include/diff_tables.inc
SELECT * FROM t1 ORDER BY a;
# BUG#59338 Inconsistency in binlog for statements that don't change any rows STATEMENT SBR
# An insert ignore that does not update anything must be written to the binary log in SBR
# and MIXED modes. We check this property by counting occurrences in t1 before and after
# the insert and comparing the binlog positions. The count should be the same in both points
# and the statement should be in the binary log.
--connection master
--let $binlog_file= query_get_value("SHOW MASTER STATUS", File, 1)
--let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1)
--let $statement_file=INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a
--eval $statement_file
sync_slave_with_master;
SELECT * FROM t1 ORDER BY a;
--let $assert_cond= COUNT(*) = 6 FROM t1
--let $assert_text= Count of elements in t1 should be 6.
--source include/assert.inc
# Now do the same for MyISAM
if (`SELECT @@BINLOG_FORMAT = 'ROW'`)
{
--let $binlog_position_cmp= =
--let $assert_cond= [SHOW MASTER STATUS, Position, 1] $binlog_position_cmp $binlog_start
--let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.
}
if (`SELECT @@BINLOG_FORMAT != 'ROW' && UPPER('$engine_type') = UPPER('Innodb')`)
{
--let $assert_cond= \'[\'SHOW BINLOG EVENTS IN "$binlog_file" FROM $binlog_start LIMIT 2, 1\', Info, 1]\' LIKE \'%$statement_file\'
--let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.
}
if (`SELECT @@BINLOG_FORMAT != 'ROW' && UPPER('$engine_type') = UPPER('MyIsam')`)
{
--let $assert_cond= \'[\'SHOW BINLOG EVENTS IN "$binlog_file" FROM $binlog_start LIMIT 1, 1\', Info, 1]\' LIKE \'%$statement_file\'
--let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.
}
--source include/assert.inc
connection master;
drop table t1;
eval CREATE TABLE t1 (
a int unsigned not null auto_increment primary key,
b int unsigned,
unique (b)
) ENGINE=$engine_type2;
INSERT INTO t1 VALUES (1, 1);
INSERT INTO t1 VALUES (2, 2);
INSERT INTO t1 VALUES (3, 3);
INSERT INTO t1 VALUES (4, 4);
INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a;
SELECT * FROM t1 ORDER BY a;
sync_slave_with_master;
SELECT * FROM t1 ORDER BY a;
connection master;
# Clean up
--connection master
drop table t1, t2;
sync_slave_with_master;
# End of 4.1 tests
--sync_slave_with_master

View File

@ -502,16 +502,16 @@ call p_verify_status_increment(2, 2, 2, 2);
--echo # 12. Read-write statement: IODKU, change 0 rows.
--echo #
insert t1 set a=2 on duplicate key update a=2;
call p_verify_status_increment(1, 0, 1, 0);
call p_verify_status_increment(2, 2, 1, 0);
commit;
call p_verify_status_increment(1, 0, 1, 0);
call p_verify_status_increment(2, 2, 1, 0);
--echo # 13. Read-write statement: INSERT IGNORE, change 0 rows.
--echo #
insert ignore t1 set a=2;
call p_verify_status_increment(1, 0, 1, 0);
call p_verify_status_increment(2, 2, 1, 0);
commit;
call p_verify_status_increment(1, 0, 1, 0);
call p_verify_status_increment(2, 2, 1, 0);
--echo # 14. Read-write statement: INSERT IGNORE, change 1 row.
--echo #

View File

@ -44,3 +44,19 @@ SELECT COUNT(*) FROM t2 IGNORE INDEX(p) WHERE p=POINTFROMTEXT('POINT(1 2)');
DROP TABLE t1, t2;
--echo End of 5.0 tests
--echo #
--echo # Test for bug #58650 "Failing assertion: primary_key_no == -1 ||
--echo # primary_key_no == 0".
--echo #
--disable_warnings
drop table if exists t1;
--enable_warnings
--echo # The minimal test case.
create table t1 (a int not null, b linestring not null, unique key b (b(12)), unique key a (a));
drop table t1;
--echo # The original test case.
create table t1 (a int not null, b linestring not null, unique key b (b(12)));
create unique index a on t1(a);
drop table t1;

View File

@ -518,21 +518,21 @@ SUCCESS
# 12. Read-write statement: IODKU, change 0 rows.
#
insert t1 set a=2 on duplicate key update a=2;
call p_verify_status_increment(1, 0, 1, 0);
call p_verify_status_increment(2, 2, 1, 0);
SUCCESS
commit;
call p_verify_status_increment(1, 0, 1, 0);
call p_verify_status_increment(2, 2, 1, 0);
SUCCESS
# 13. Read-write statement: INSERT IGNORE, change 0 rows.
#
insert ignore t1 set a=2;
call p_verify_status_increment(1, 0, 1, 0);
call p_verify_status_increment(2, 2, 1, 0);
SUCCESS
commit;
call p_verify_status_increment(1, 0, 1, 0);
call p_verify_status_increment(2, 2, 1, 0);
SUCCESS
# 14. Read-write statement: INSERT IGNORE, change 1 row.

View File

@ -19,13 +19,16 @@ INSERT INTO t1 VALUES();
SELECT * FROM t1;
a b c d e f
0 foo 0000-00-00
INSERT INTO t1 VALUES(default,default,default,default,default,default);
SELECT * FROM t1;
a b c d e f
0 foo 0000-00-00
0 foo 0000-00-00
INSERT INTO t1 VALUES(0,'abc','def','ghi','bar','1999-12-31');
SELECT * FROM t1;
a b c d e f
0 foo 0000-00-00
0 foo 0000-00-00
0 abc def ghi bar 1999-12-31
# === insert failures ===
INSERT INTO t1 VALUES(NULL,'ab','a','b','foo','2007-01-01');

View File

@ -1301,6 +1301,24 @@ SELECT '2008-02-18' + INTERVAL 1 FRAC_SECOND;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FRAC_SECOND' at line 1
SELECT '2008-02-18' - INTERVAL 1 FRAC_SECOND;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FRAC_SECOND' at line 1
#
# Bug #52315 part 2 : utc_date() crashes when system time > year 2037
#
SET TIMESTAMP=-147490000;
SELECT UTC_TIMESTAMP();
SET TIMESTAMP=2147483648;
SELECT UTC_TIMESTAMP();
SET TIMESTAMP=2147483646;
SELECT UTC_TIMESTAMP();
SET TIMESTAMP=2147483647;
SELECT UTC_TIMESTAMP();
SET TIMESTAMP=0;
SELECT UTC_TIMESTAMP();
SET TIMESTAMP=-1;
SELECT UTC_TIMESTAMP();
SET TIMESTAMP=1;
SELECT UTC_TIMESTAMP();
SET TIMESTAMP=0;
End of 5.0 tests
select date_sub("0050-01-01 00:00:01",INTERVAL 2 SECOND);
date_sub("0050-01-01 00:00:01",INTERVAL 2 SECOND)

View File

@ -960,6 +960,18 @@ COUNT(*)
2
DROP TABLE t1, t2;
End of 5.0 tests
#
# Test for bug #58650 "Failing assertion: primary_key_no == -1 ||
# primary_key_no == 0".
#
drop table if exists t1;
# The minimal test case.
create table t1 (a int not null, b linestring not null, unique key b (b(12)), unique key a (a));
drop table t1;
# The original test case.
create table t1 (a int not null, b linestring not null, unique key b (b(12)));
create unique index a on t1(a);
drop table t1;
create table `t1` (`col002` point)engine=myisam;
insert into t1 values (),(),();
select min(`col002`) from t1 union select `col002` from t1;

View File

@ -4,3 +4,7 @@ select 1;
SHOW VARIABLES like 'slave_skip_errors';
Variable_name Value
slave_skip_errors OFF
#
# Bug#58026: massive recursion and crash in regular expression handling
#
SELECT '1' RLIKE RPAD('1', 10000, '(');

View File

@ -1666,4 +1666,105 @@ c_key c_notkey
1 1
3 3
DROP TABLE t1;
#
# Bug #57030: 'BETWEEN' evaluation is incorrect
#
CREATE TABLE t1(pk INT PRIMARY KEY, i4 INT);
CREATE UNIQUE INDEX i4_uq ON t1(i4);
INSERT INTO t1 VALUES (1,10), (2,20), (3,30);
EXPLAIN
SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 10;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const i4_uq i4_uq 5 const 1
SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 10;
pk i4
1 10
EXPLAIN
SELECT * FROM t1 WHERE 10 BETWEEN i4 AND i4;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const i4_uq i4_uq 5 const 1
SELECT * FROM t1 WHERE 10 BETWEEN i4 AND i4;
pk i4
1 10
EXPLAIN
SELECT * FROM t1 WHERE 10 BETWEEN 10 AND i4;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range i4_uq i4_uq 5 NULL 3 Using where
SELECT * FROM t1 WHERE 10 BETWEEN 10 AND i4;
pk i4
1 10
2 20
3 30
EXPLAIN
SELECT * FROM t1 WHERE 10 BETWEEN i4 AND 10;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range i4_uq i4_uq 5 NULL 1 Using where
SELECT * FROM t1 WHERE 10 BETWEEN i4 AND 10;
pk i4
1 10
EXPLAIN
SELECT * FROM t1 WHERE 10 BETWEEN 10 AND 10;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
SELECT * FROM t1 WHERE 10 BETWEEN 10 AND 10;
pk i4
1 10
2 20
3 30
EXPLAIN
SELECT * FROM t1 WHERE 10 BETWEEN 11 AND 11;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
SELECT * FROM t1 WHERE 10 BETWEEN 11 AND 11;
pk i4
EXPLAIN
SELECT * FROM t1 WHERE 10 BETWEEN 100 AND 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
SELECT * FROM t1 WHERE 10 BETWEEN 100 AND 0;
pk i4
EXPLAIN
SELECT * FROM t1 WHERE i4 BETWEEN 100 AND 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
SELECT * FROM t1 WHERE i4 BETWEEN 100 AND 0;
pk i4
EXPLAIN
SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 99999999999999999;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range i4_uq i4_uq 5 NULL 2 Using where
SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 99999999999999999;
pk i4
1 10
2 20
3 30
EXPLAIN
SELECT * FROM t1 WHERE i4 BETWEEN 999999999999999 AND 30;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
SELECT * FROM t1 WHERE i4 BETWEEN 999999999999999 AND 30;
pk i4
EXPLAIN
SELECT * FROM t1 WHERE i4 BETWEEN 10 AND '20';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range i4_uq i4_uq 5 NULL 1 Using where
SELECT * FROM t1 WHERE i4 BETWEEN 10 AND '20';
pk i4
1 10
2 20
EXPLAIN
SELECT * FROM t1, t1 as t2 WHERE t2.pk BETWEEN t1.i4 AND t1.i4;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL i4_uq NULL NULL NULL 3
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.i4 1 Using where
SELECT * FROM t1, t1 as t2 WHERE t2.pk BETWEEN t1.i4 AND t1.i4;
pk i4 pk i4
EXPLAIN
SELECT * FROM t1, t1 as t2 WHERE t1.i4 BETWEEN t2.pk AND t2.pk;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL i4_uq NULL NULL NULL 3
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.i4 1 Using where
SELECT * FROM t1, t1 as t2 WHERE t1.i4 BETWEEN t2.pk AND t2.pk;
pk i4 pk i4
DROP TABLE t1;
End of 5.1 tests

View File

@ -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;

View File

@ -585,5 +585,17 @@ COUNT(*)
2
DROP TABLE t1, t2;
End of 5.0 tests
#
# Test for bug #58650 "Failing assertion: primary_key_no == -1 ||
# primary_key_no == 0".
#
drop table if exists t1;
# The minimal test case.
create table t1 (a int not null, b linestring not null, unique key b (b(12)), unique key a (a));
drop table t1;
# The original test case.
create table t1 (a int not null, b linestring not null, unique key b (b(12)));
create unique index a on t1(a);
drop table t1;
create table t1 (g geometry not null, spatial gk(g)) engine=innodb;
ERROR HY000: The used table type doesn't support SPATIAL indexes

View File

@ -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;

View File

@ -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` (

View File

@ -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;

View File

@ -585,5 +585,17 @@ COUNT(*)
2
DROP TABLE t1, t2;
End of 5.0 tests
#
# Test for bug #58650 "Failing assertion: primary_key_no == -1 ||
# primary_key_no == 0".
#
drop table if exists t1;
# The minimal test case.
create table t1 (a int not null, b linestring not null, unique key b (b(12)), unique key a (a));
drop table t1;
# The original test case.
create table t1 (a int not null, b linestring not null, unique key b (b(12)));
create unique index a on t1(a);
drop table t1;
create table t1 (g geometry not null, spatial gk(g)) engine=innodb;
ERROR HY000: The used table type doesn't support SPATIAL indexes

View File

@ -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;

View File

@ -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;

View File

@ -0,0 +1,29 @@
include/master-slave.inc
[connection master]
CREATE TABLE t1 (
a INT UNSIGNED NOT NULL PRIMARY KEY
) ENGINE=innodb;
CREATE TABLE t2 (
a INT UNSIGNED
) ENGINE=innodb;
INSERT INTO t1 VALUES (1);
INSERT INTO t2 VALUES (1);
INSERT INTO t1 SELECT t2.a FROM t2 ORDER BY t2.a ON DUPLICATE KEY UPDATE t1.a= t1.a;
include/assert.inc [Sum of elements in t1 should be 1.]
include/assert.inc [In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.]
include/diff_tables.inc [master:test.t1 , slave:test.t1]
drop table t1, t2;
CREATE TABLE t1 (
a INT UNSIGNED NOT NULL PRIMARY KEY
) ENGINE=myisam;
CREATE TABLE t2 (
a INT UNSIGNED
) ENGINE=myisam;
INSERT INTO t1 VALUES (1);
INSERT INTO t2 VALUES (1);
INSERT INTO t1 SELECT t2.a FROM t2 ORDER BY t2.a ON DUPLICATE KEY UPDATE t1.a= t1.a;
include/assert.inc [Sum of elements in t1 should be 1.]
include/assert.inc [In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.]
include/diff_tables.inc [master:test.t1 , slave:test.t1]
drop table t1, t2;
include/rpl_end.inc

View File

@ -20,48 +20,36 @@ INSERT INTO t2 VALUES (4, 3);
INSERT INTO t2 VALUES (5, 4);
INSERT INTO t2 VALUES (6, 6);
INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a;
SELECT * FROM t1 ORDER BY a;
a b
1 1
2 2
3 3
4 4
5 5
6 6
SELECT * FROM t1 ORDER BY a;
a b
1 1
2 2
3 3
4 4
5 5
6 6
drop table t1;
include/assert.inc [Count of elements in t1 should be 6.]
include/diff_tables.inc [master:test.t1 , slave:test.t1]
INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a;
include/assert.inc [Count of elements in t1 should be 6.]
include/assert.inc [In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.]
drop table t1, t2;
CREATE TABLE t1 (
a int unsigned not null auto_increment primary key,
b int unsigned,
unique (b)
) ENGINE=myisam;
INSERT INTO t1 VALUES (1, 1);
INSERT INTO t1 VALUES (2, 2);
INSERT INTO t1 VALUES (3, 3);
INSERT INTO t1 VALUES (4, 4);
CREATE TABLE t2 (
a int unsigned, # to force INSERT SELECT to have a certain order
b int unsigned
) ENGINE=myisam;
INSERT INTO t1 VALUES (NULL, 1);
INSERT INTO t1 VALUES (NULL, 2);
INSERT INTO t1 VALUES (NULL, 3);
INSERT INTO t1 VALUES (NULL, 4);
INSERT INTO t2 VALUES (1, 1);
INSERT INTO t2 VALUES (2, 2);
INSERT INTO t2 VALUES (3, 5);
INSERT INTO t2 VALUES (4, 3);
INSERT INTO t2 VALUES (5, 4);
INSERT INTO t2 VALUES (6, 6);
INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a;
SELECT * FROM t1 ORDER BY a;
a b
1 1
2 2
3 3
4 4
5 5
6 6
SELECT * FROM t1 ORDER BY a;
a b
1 1
2 2
3 3
4 4
5 5
6 6
include/assert.inc [Count of elements in t1 should be 6.]
include/diff_tables.inc [master:test.t1 , slave:test.t1]
INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a;
include/assert.inc [Count of elements in t1 should be 6.]
include/assert.inc [In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.]
drop table t1, t2;
include/rpl_end.inc

View File

@ -11,7 +11,6 @@
##############################################################################
rpl_row_create_table : Bug#51574 Feb 27 2010 andrei failed different way than earlier with bug#45576
rpl_log_pos : BUG#55675 Sep 10 2010 27 2010 alfranio rpl.rpl_log_pos fails sporadically with error binlog truncated in the middle
rpl_get_master_version_and_clock : Bug#59178 Jan 05 2011 joro Valgrind warnings rpl_get_master_version_and_clock
rpl_row_until : BUG#59543 Jan 26 2011 alfranio Replication test from eits suite rpl_row_until times out
rpl_stm_until : BUG#59543 Jan 26 2011 alfranio Replication test from eits suite rpl_row_until times out

View File

@ -0,0 +1,14 @@
#########################################
# Wrapper for rpl_insert_duplicate.test #
#########################################
-- source include/master-slave.inc
-- source include/have_innodb.inc
#-- source include/have_binlog_format_mixed_or_statement.inc
let $engine_type=innodb;
-- source extra/rpl_tests/rpl_insert_duplicate.test
let $engine_type=myisam;
-- source extra/rpl_tests/rpl_insert_duplicate.test
--source include/rpl_end.inc

View File

@ -4,7 +4,11 @@
-- source include/not_ndb_default.inc
-- source include/have_innodb.inc
-- source include/master-slave.inc
let $engine_type=innodb;
let $engine_type2=myisam;
-- let $engine_type=innodb
-- source extra/rpl_tests/rpl_insert_ignore.test
-- let $engine_type=myisam
-- source extra/rpl_tests/rpl_insert_ignore.test
--source include/rpl_end.inc

View File

@ -55,10 +55,8 @@ INSERT INTO t1 VALUES();
SELECT * FROM t1;
-- disable_warnings
# NOTE - Test disabled due to enum crash for this INSERT
# See Bug#33717 - INSERT...(default) fails for enum.
# Crashes CSV tables, loads spaces for MyISAM
#INSERT INTO t1 VALUES(default,default,default,default,default,default);
# Bug#33717 - INSERT...(default) fails for enum.
INSERT INTO t1 VALUES(default,default,default,default,default,default);
-- enable_warnings
SELECT * FROM t1;

View File

@ -819,6 +819,28 @@ SELECT '2008-02-18' + INTERVAL 1 FRAC_SECOND;
--error ER_PARSE_ERROR
SELECT '2008-02-18' - INTERVAL 1 FRAC_SECOND;
--echo #
--echo # Bug #52315 part 2 : utc_date() crashes when system time > year 2037
--echo #
--disable_result_log
--error ER_WRONG_VALUE_FOR_VAR
SET TIMESTAMP=-147490000; SELECT UTC_TIMESTAMP();
--error ER_WRONG_VALUE_FOR_VAR
SET TIMESTAMP=2147483648; SELECT UTC_TIMESTAMP();
SET TIMESTAMP=2147483646; SELECT UTC_TIMESTAMP();
SET TIMESTAMP=2147483647; SELECT UTC_TIMESTAMP();
SET TIMESTAMP=0; SELECT UTC_TIMESTAMP();
--error ER_WRONG_VALUE_FOR_VAR
SET TIMESTAMP=-1; SELECT UTC_TIMESTAMP();
SET TIMESTAMP=1; SELECT UTC_TIMESTAMP();
--enable_result_log
#reset back the timestamp value
SET TIMESTAMP=0;
--echo End of 5.0 tests
#

View File

@ -42,4 +42,14 @@ select 1;
SHOW VARIABLES like 'slave_skip_errors';
--echo #
--echo # Bug#58026: massive recursion and crash in regular expression handling
--echo #
--disable_result_log
--error ER_STACK_OVERRUN_NEED_MORE
SELECT '1' RLIKE RPAD('1', 10000, '(');
--enable_result_log
# End of 5.1 tests

View File

@ -1325,4 +1325,71 @@ SELECT * FROM t1 WHERE 2 NOT BETWEEN c_notkey AND c_key;
DROP TABLE t1;
--echo #
--echo # Bug #57030: 'BETWEEN' evaluation is incorrect
--echo #
# Test some BETWEEN predicates which does *not* follow the
# 'normal' pattern of <field> BETWEEN <low const> AND <high const>
CREATE TABLE t1(pk INT PRIMARY KEY, i4 INT);
CREATE UNIQUE INDEX i4_uq ON t1(i4);
INSERT INTO t1 VALUES (1,10), (2,20), (3,30);
EXPLAIN
SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 10;
SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 10;
EXPLAIN
SELECT * FROM t1 WHERE 10 BETWEEN i4 AND i4;
SELECT * FROM t1 WHERE 10 BETWEEN i4 AND i4;
EXPLAIN
SELECT * FROM t1 WHERE 10 BETWEEN 10 AND i4;
SELECT * FROM t1 WHERE 10 BETWEEN 10 AND i4;
EXPLAIN
SELECT * FROM t1 WHERE 10 BETWEEN i4 AND 10;
SELECT * FROM t1 WHERE 10 BETWEEN i4 AND 10;
EXPLAIN
SELECT * FROM t1 WHERE 10 BETWEEN 10 AND 10;
SELECT * FROM t1 WHERE 10 BETWEEN 10 AND 10;
EXPLAIN
SELECT * FROM t1 WHERE 10 BETWEEN 11 AND 11;
SELECT * FROM t1 WHERE 10 BETWEEN 11 AND 11;
EXPLAIN
SELECT * FROM t1 WHERE 10 BETWEEN 100 AND 0;
SELECT * FROM t1 WHERE 10 BETWEEN 100 AND 0;
EXPLAIN
SELECT * FROM t1 WHERE i4 BETWEEN 100 AND 0;
SELECT * FROM t1 WHERE i4 BETWEEN 100 AND 0;
EXPLAIN
SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 99999999999999999;
SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 99999999999999999;
EXPLAIN
SELECT * FROM t1 WHERE i4 BETWEEN 999999999999999 AND 30;
SELECT * FROM t1 WHERE i4 BETWEEN 999999999999999 AND 30;
EXPLAIN
SELECT * FROM t1 WHERE i4 BETWEEN 10 AND '20';
SELECT * FROM t1 WHERE i4 BETWEEN 10 AND '20';
#Should detect the EQ_REF 't2.pk=t1.i4'
EXPLAIN
SELECT * FROM t1, t1 as t2 WHERE t2.pk BETWEEN t1.i4 AND t1.i4;
SELECT * FROM t1, t1 as t2 WHERE t2.pk BETWEEN t1.i4 AND t1.i4;
EXPLAIN
SELECT * FROM t1, t1 as t2 WHERE t1.i4 BETWEEN t2.pk AND t2.pk;
SELECT * FROM t1, t1 as t2 WHERE t1.i4 BETWEEN t2.pk AND t2.pk;
DROP TABLE t1;
--echo End of 5.1 tests

View File

@ -791,7 +791,7 @@ SET @@myisam_mmap_size= 500M;
--echo # Bug #52315: utc_date() crashes when system time > year 2037
--echo #
--error 0, ER_UNKNOWN_ERROR
--error 0, ER_WRONG_VALUE_FOR_VAR
SET TIMESTAMP=2*1024*1024*1024;
--echo #Should not crash
--disable_result_log

View File

@ -28,6 +28,7 @@ typedef struct {
/* === regcomp.c === */
typedef int (*my_regex_stack_check_t)();
extern int my_regcomp(my_regex_t *, const char *, int, CHARSET_INFO *charset);
#define REG_BASIC 0000
#define REG_EXTENDED 0001
@ -76,7 +77,8 @@ extern void my_regfree(my_regex_t *);
/* === reginit.c === */
extern void my_regex_init(CHARSET_INFO *cs); /* Should be called for multithread progs */
/* Should be called for multithread progs */
extern void my_regex_init(CHARSET_INFO *cs, my_regex_stack_check_t func);
extern void my_regex_end(void); /* If one wants a clean end */
#ifdef __cplusplus

View File

@ -31,6 +31,9 @@ struct parse {
CHARSET_INFO *charset; /* for ctype things */
};
/* Check if there is enough stack space for recursion. */
my_regex_stack_check_t my_regex_enough_mem_in_stack= NULL;
#include "regcomp.ih"
static char nuls[10]; /* place to point scanner in event of error */
@ -117,7 +120,7 @@ CHARSET_INFO *charset;
# define GOODFLAGS(f) ((f)&~REG_DUMP)
#endif
my_regex_init(charset); /* Init cclass if neaded */
my_regex_init(charset, NULL); /* Init cclass if neaded */
preg->charset=charset;
cflags = GOODFLAGS(cflags);
if ((cflags&REG_EXTENDED) && (cflags&REG_NOSPEC))
@ -222,7 +225,15 @@ int stop; /* character this ERE should end at */
/* do a bunch of concatenated expressions */
conc = HERE();
while (MORE() && (c = PEEK()) != '|' && c != stop)
p_ere_exp(p);
{
if (my_regex_enough_mem_in_stack &&
my_regex_enough_mem_in_stack())
{
SETERROR(REG_ESPACE);
return;
}
p_ere_exp(p);
}
if(REQUIRE(HERE() != conc, REG_EMPTY)) {}/* require nonempty */
if (!EAT('|'))

View File

@ -4,10 +4,12 @@
#include <m_ctype.h>
#include <m_string.h>
#include "cclass.h"
#include "my_regex.h"
static my_bool regex_inited=0;
extern my_regex_stack_check_t my_regex_enough_mem_in_stack;
void my_regex_init(CHARSET_INFO *cs)
void my_regex_init(CHARSET_INFO *cs, my_regex_stack_check_t func)
{
char buff[CCLASS_LAST][256];
int count[CCLASS_LAST];
@ -16,6 +18,7 @@ void my_regex_init(CHARSET_INFO *cs)
if (!regex_inited)
{
regex_inited=1;
my_regex_enough_mem_in_stack= func;
bzero((uchar*) &count,sizeof(count));
for (i=1 ; i<= 255; i++)
@ -74,6 +77,7 @@ void my_regex_end()
int i;
for (i=0; i < CCLASS_LAST ; i++)
free((char*) cclasses[i].chars);
my_regex_enough_mem_in_stack= NULL;
regex_inited=0;
}
}

View File

@ -992,7 +992,7 @@ my_system_gmt_sec(const MYSQL_TIME *t_src, long *my_timezone,
with unsigned time_t tmp+= shift*86400L might result in a number,
larger then TIMESTAMP_MAX_VALUE, so another check will work.
*/
if ((tmp < TIMESTAMP_MIN_VALUE) || (tmp > TIMESTAMP_MAX_VALUE))
if (!IS_TIME_T_VALID_FOR_TIMESTAMP(tmp))
tmp= 0;
return (my_time_t) tmp;

View File

@ -9476,6 +9476,7 @@ void Create_field::create_length_to_internal_length(void)
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_GEOMETRY:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VARCHAR:

View File

@ -3034,6 +3034,19 @@ sizeof(load_default_groups)/sizeof(load_default_groups[0]);
#endif
#ifndef EMBEDDED_LIBRARY
static
int
check_enough_stack_size()
{
uchar stack_top;
return check_stack_overrun(current_thd, STACK_MIN_SIZE,
&stack_top);
}
#endif
/**
Initialize one of the global date/time format variables.
@ -3236,12 +3249,6 @@ static int init_common_variables(const char *conf_file_name, int argc,
max_system_variables.pseudo_thread_id= (ulong)~0;
server_start_time= flush_status_time= my_time(0);
/* TODO: remove this when my_time_t is 64 bit compatible */
if (server_start_time >= (time_t) MY_TIME_T_MAX)
{
sql_print_error("This MySQL server doesn't support dates later then 2038");
return 1;
}
rpl_filter= new Rpl_filter;
binlog_filter= new Rpl_filter;
@ -3280,6 +3287,13 @@ static int init_common_variables(const char *conf_file_name, int argc,
*/
mysql_bin_log.init_pthread_objects();
/* TODO: remove this when my_time_t is 64 bit compatible */
if (!IS_TIME_T_VALID_FOR_TIMESTAMP(server_start_time))
{
sql_print_error("This MySQL server doesn't support dates later then 2038");
return 1;
}
if (gethostname(glob_hostname,sizeof(glob_hostname)) < 0)
{
strmake(glob_hostname, STRING_WITH_LEN("localhost"));
@ -3414,7 +3428,11 @@ static int init_common_variables(const char *conf_file_name, int argc,
#endif
mysys_uses_curses=0;
#ifdef USE_REGEX
my_regex_init(&my_charset_latin1);
#ifndef EMBEDDED_LIBRARY
my_regex_init(&my_charset_latin1, check_enough_stack_size);
#else
my_regex_init(&my_charset_latin1, NULL);
#endif
#endif
/*
Process a comma-separated character set list and choose

View File

@ -2699,14 +2699,14 @@ int set_var_collation_client::update(THD *thd)
bool sys_var_timestamp::check(THD *thd, set_var *var)
{
time_t val;
longlong val;
var->save_result.ulonglong_value= var->value->val_int();
val= (time_t) var->save_result.ulonglong_value;
if (val < (time_t) MY_TIME_T_MIN || val > (time_t) MY_TIME_T_MAX)
val= (longlong) var->save_result.ulonglong_value;
if (val != 0 && // this is how you set the default value
(val < TIMESTAMP_MIN_VALUE || val > TIMESTAMP_MAX_VALUE))
{
my_message(ER_UNKNOWN_ERROR,
"This version of MySQL doesn't support dates later than 2038",
MYF(0));
char buf[64];
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "timestamp", llstr(val, buf));
return TRUE;
}
return FALSE;

View File

@ -2036,7 +2036,7 @@ public:
/*TODO: this will be obsolete when we have support for 64 bit my_time_t */
inline bool is_valid_time()
{
return (start_time < (time_t) MY_TIME_T_MAX);
return (IS_TIME_T_VALID_FOR_TIMESTAMP(start_time));
}
void set_time_after_lock() { utime_after_lock= my_micro_time(); }
ulonglong current_utime() { return my_micro_time(); }

View File

@ -881,7 +881,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
*/
query_cache_invalidate3(thd, table_list, 1);
}
if ((changed && error <= 0) ||
if (error <= 0 ||
thd->transaction.stmt.modified_non_trans_table ||
was_insert_delayed)
{

View File

@ -545,8 +545,10 @@ impossible position";
while (!net->error && net->vio != 0 && !thd->killed)
{
my_off_t prev_pos= pos;
while (!(error = Log_event::read_log_event(&log, packet, log_lock)))
{
prev_pos= my_b_tell(&log);
#ifndef DBUG_OFF
if (max_binlog_dump_events && !left_events--)
{
@ -613,8 +615,13 @@ impossible position";
here we were reading binlog that was not closed properly (as a result
of a crash ?). treat any corruption as EOF
*/
if (binlog_can_be_corrupted && error != LOG_READ_MEM)
if (binlog_can_be_corrupted &&
error != LOG_READ_MEM && error != LOG_READ_EOF)
{
my_b_seek(&log, prev_pos);
error=LOG_READ_EOF;
}
/*
TODO: now that we are logging the offset, check to make sure
the recorded offset and the actual match.

View File

@ -3349,26 +3349,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
eq_func is NEVER true when num_values > 1
*/
if (!eq_func)
{
/*
Additional optimization: if we're processing
"t.key BETWEEN c1 AND c1" then proceed as if we were processing
"t.key = c1".
TODO: This is a very limited fix. A more generic fix is possible.
There are 2 options:
A) Make equality propagation code be able to handle BETWEEN
(including cases like t1.key BETWEEN t2.key AND t3.key)
B) Make range optimizer to infer additional "t.key = c" equalities
and use them in equality propagation process (see details in
OptimizerKBAndTodo)
*/
if ((cond->functype() != Item_func::BETWEEN) ||
((Item_func_between*) cond)->negated ||
!value[0]->eq(value[1], field->binary()))
return;
eq_func= TRUE;
}
return;
if (field->result_type() == STRING_RESULT)
{
if ((*value)->result_type() != STRING_RESULT)
@ -3564,9 +3545,65 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
case Item_func::OPTIMIZE_KEY:
{
Item **values;
// BETWEEN, IN, NE
if (is_local_field (cond_func->key_item()) &&
!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
/*
Build list of possible keys for 'a BETWEEN low AND high'.
It is handled similar to the equivalent condition
'a >= low AND a <= high':
*/
if (cond_func->functype() == Item_func::BETWEEN)
{
Item_field *field_item;
bool equal_func= FALSE;
uint num_values= 2;
values= cond_func->arguments();
bool binary_cmp= (values[0]->real_item()->type() == Item::FIELD_ITEM)
? ((Item_field*)values[0]->real_item())->field->binary()
: TRUE;
/*
Additional optimization: If 'low = high':
Handle as if the condition was "t.key = low".
*/
if (!((Item_func_between*)cond_func)->negated &&
values[1]->eq(values[2], binary_cmp))
{
equal_func= TRUE;
num_values= 1;
}
/*
Append keys for 'field <cmp> value[]' if the
condition is of the form::
'<field> BETWEEN value[1] AND value[2]'
*/
if (is_local_field (values[0]))
{
field_item= (Item_field *) (values[0]->real_item());
add_key_equal_fields(key_fields, *and_level, cond_func,
field_item, equal_func, &values[1],
num_values, usable_tables, sargables);
}
/*
Append keys for 'value[0] <cmp> field' if the
condition is of the form:
'value[0] BETWEEN field1 AND field2'
*/
for (uint i= 1; i <= num_values; i++)
{
if (is_local_field (values[i]))
{
field_item= (Item_field *) (values[i]->real_item());
add_key_equal_fields(key_fields, *and_level, cond_func,
field_item, equal_func, values,
1, usable_tables, sargables);
}
}
} // if ( ... Item_func::BETWEEN)
// IN, NE
else if (is_local_field (cond_func->key_item()) &&
!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
{
values= cond_func->arguments()+1;
if (cond_func->functype() == Item_func::NE_FUNC &&
@ -3580,21 +3617,6 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
cond_func->argument_count()-1,
usable_tables, sargables);
}
if (cond_func->functype() == Item_func::BETWEEN)
{
values= cond_func->arguments();
for (uint i= 1 ; i < cond_func->argument_count() ; i++)
{
Item_field *field_item;
if (is_local_field (cond_func->arguments()[i]))
{
field_item= (Item_field *) (cond_func->arguments()[i]->real_item());
add_key_equal_fields(key_fields, *and_level, cond_func,
field_item, 0, values, 1, usable_tables,
sargables);
}
}
}
break;
}
case Item_func::OPTIMIZE_OP:

View File

@ -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));
memset(n_diff, 0, (n_cols + 1) * sizeof(ib_longlong));
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;
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;
/* 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_free(n_diff);
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
mem_heap_free(heap);
}
/*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/

View File

@ -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);

View File

@ -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),

View File

@ -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(

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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));
}

View File

@ -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. */

View File

@ -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 */

View File

@ -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

View File

@ -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. */

View File

@ -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

View File

@ -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. */

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}
/*******************************************************************

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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;
/* 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_free(n_diff);
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
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);
}
}

View File

@ -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);

View File

@ -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();

View File

@ -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();

View File

@ -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();
buf_pool_mutex_exit();
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();
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);

View File

@ -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);

View File

@ -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),

View File

@ -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(

View File

@ -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

View File

@ -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);

View File

@ -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. */

View File

@ -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 */

View File

@ -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;

View File

@ -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

View File

@ -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));
}

View File

@ -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 {

View File

@ -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 */

View File

@ -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

View File

@ -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.

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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 */

View File

@ -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

View File

@ -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);

View File

@ -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. */

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}
/***************************************************************//**

View File

@ -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);
}