Commit 4ea1b2fc authored by Mats Kindahl's avatar Mats Kindahl

Merging with mysql-5.5-bugfixing.

parents 34b8e774 d6d16303
perl mysql-test-run.pl --timer --force --comment=1st --experimental=collections/default.experimental 1st
perl mysql-test-run.pl --timer --force --comment=big-tests --experimental=collections/default.experimental --vardir=var-big-tests --big-test --testcase-timeout=60 --suite-timeout=600 parts.part_supported_sql_func_innodb parts.partition_alter1_1_2_innodb parts.partition_alter1_1_2_ndb parts.partition_alter1_1_ndb parts.partition_alter1_2_innodb parts.partition_alter1_2_ndb parts.partition_alter2_1_1_innodb parts.partition_alter2_1_2_innodb parts.partition_alter2_2_2_innodb parts.partition_alter4_innodb main.variables-big rpl_ndb.rpl_truncate_7ndb_2
perl mysql-test-run.pl --timer --force --comment=big-tests --experimental=collections/default.experimental --vardir=var-big-tests --big-test --testcase-timeout=60 --suite-timeout=600 large_tests.alter_table main.alter_table-big main.archive-big main.count_distinct3 main.create-big main.events_stress main.events_time_zone main.information_schema-big main.log_tables-big main.merge-big main.mysqlbinlog_row_big main.read_many_rows_innodb main.ssl-big main.sum_distinct-big main.type_newdecimal-big main.variables-big parts.part_supported_sql_func_innodb parts.partition_alter1_1_2_innodb parts.partition_alter1_1_2_ndb parts.partition_alter1_1_ndb parts.partition_alter1_2_innodb parts.partition_alter1_2_ndb parts.partition_alter2_1_1_innodb parts.partition_alter2_1_2_innodb parts.partition_alter2_2_2_innodb parts.partition_alter4_innodb rpl_ndb.rpl_truncate_7ndb_2
......@@ -30,6 +30,7 @@ FILES TABLE_SCHEMA
GLOBAL_STATUS VARIABLE_NAME
GLOBAL_VARIABLES VARIABLE_NAME
KEY_COLUMN_USAGE CONSTRAINT_SCHEMA
PARAMETERS SPECIFIC_SCHEMA
PARTITIONS TABLE_SCHEMA
PLUGINS PLUGIN_NAME
PROCESSLIST ID
......@@ -42,6 +43,7 @@ SESSION_STATUS VARIABLE_NAME
SESSION_VARIABLES VARIABLE_NAME
STATISTICS TABLE_SCHEMA
TABLES TABLE_SCHEMA
TABLESPACES TABLESPACE_NAME
TABLE_CONSTRAINTS CONSTRAINT_SCHEMA
TABLE_PRIVILEGES TABLE_SCHEMA
TRIGGERS TRIGGER_SCHEMA
......@@ -74,6 +76,7 @@ FILES TABLE_SCHEMA
GLOBAL_STATUS VARIABLE_NAME
GLOBAL_VARIABLES VARIABLE_NAME
KEY_COLUMN_USAGE CONSTRAINT_SCHEMA
PARAMETERS SPECIFIC_SCHEMA
PARTITIONS TABLE_SCHEMA
PLUGINS PLUGIN_NAME
PROCESSLIST ID
......@@ -86,6 +89,7 @@ SESSION_STATUS VARIABLE_NAME
SESSION_VARIABLES VARIABLE_NAME
STATISTICS TABLE_SCHEMA
TABLES TABLE_SCHEMA
TABLESPACES TABLESPACE_NAME
TABLE_CONSTRAINTS CONSTRAINT_SCHEMA
TABLE_PRIVILEGES TABLE_SCHEMA
TRIGGERS TRIGGER_SCHEMA
......
......@@ -14,3 +14,32 @@ flush privileges;
ERROR HY000: Table 'host' was not locked with LOCK TABLES
unlock tables;
drop table t1;
#
# Bug#54812: assert in Diagnostics_area::set_ok_status during EXPLAIN
#
CREATE USER nopriv_user@localhost;
connection: default
DROP TABLE IF EXISTS t1,t2,t3;
DROP FUNCTION IF EXISTS f;
CREATE TABLE t1 (key1 INT PRIMARY KEY);
CREATE TABLE t2 (key2 INT);
INSERT INTO t1 VALUES (1),(2);
CREATE FUNCTION f() RETURNS INT RETURN 1;
GRANT FILE ON *.* TO 'nopriv_user'@'localhost';
FLUSH PRIVILEGES;
connection: con1
SELECT MAX(key1) FROM t1 WHERE f() < 1 INTO OUTFILE 'mytest';
ERROR 42000: execute command denied to user 'nopriv_user'@'localhost' for routine 'test.f'
INSERT INTO t2 SELECT MAX(key1) FROM t1 WHERE f() < 1;
ERROR 42000: execute command denied to user 'nopriv_user'@'localhost' for routine 'test.f'
SELECT MAX(key1) INTO @dummy FROM t1 WHERE f() < 1;
ERROR 42000: execute command denied to user 'nopriv_user'@'localhost' for routine 'test.f'
CREATE TABLE t3 (i INT) AS SELECT MAX(key1) FROM t1 WHERE f() < 1;
ERROR 42000: execute command denied to user 'nopriv_user'@'localhost' for routine 'test.f'
connection: default
DROP TABLE t1,t2;
DROP FUNCTION f;
DROP USER nopriv_user@localhost;
#
# End Bug#54812
#
drop table if exists t1, t2;
#
# Bug#57778: failed primary key add to partitioned innodb table
# inconsistent and crashes
#
CREATE TABLE t1 (a INT NOT NULL, b INT NOT NULL)
PARTITION BY KEY (a) PARTITIONS 2;
INSERT INTO t1 VALUES (0,1), (0,2);
ALTER TABLE t1 ADD PRIMARY KEY (a);
ERROR 23000: Duplicate entry '0' for key 'PRIMARY'
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) NOT NULL,
`b` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
/*!50100 PARTITION BY KEY (a)
PARTITIONS 2 */
SELECT * FROM t1;
a b
0 1
0 2
UPDATE t1 SET a = 1, b = 1 WHERE a = 0 AND b = 2;
ALTER TABLE t1 ADD PRIMARY KEY (a);
SELECT * FROM t1;
a b
1 1
0 1
ALTER TABLE t1 DROP PRIMARY KEY;
SELECT * FROM t1;
a b
1 1
0 1
DROP TABLE t1;
#
# Bug#57113: ha_partition::extra(ha_extra_function):
# Assertion `m_extra_cache' failed
CREATE TABLE t1
......
SET SESSION transaction_prealloc_size=1024*1024*1024*1;
SHOW PROCESSLIST;
Id User Host db Command Time State Info
<Id> root localhost test Query <Time> NULL SHOW PROCESSLIST
<Id> root <Host> test Query <Time> NULL SHOW PROCESSLIST
SET SESSION transaction_prealloc_size=1024*1024*1024*2;
SHOW PROCESSLIST;
Id User Host db Command Time State Info
<Id> root localhost test Query <Time> NULL SHOW PROCESSLIST
<Id> root <Host> test Query <Time> NULL SHOW PROCESSLIST
SET SESSION transaction_prealloc_size=1024*1024*1024*3;
SHOW PROCESSLIST;
Id User Host db Command Time State Info
<Id> root localhost test Query <Time> NULL SHOW PROCESSLIST
<Id> root <Host> test Query <Time> NULL SHOW PROCESSLIST
SET SESSION transaction_prealloc_size=1024*1024*1024*4;
SHOW PROCESSLIST;
Id User Host db Command Time State Info
<Id> root localhost test Query <Time> NULL SHOW PROCESSLIST
<Id> root <Host> test Query <Time> NULL SHOW PROCESSLIST
SET SESSION transaction_prealloc_size=1024*1024*1024*5;
SHOW PROCESSLIST;
Id User Host db Command Time State Info
<Id> root localhost test Query <Time> NULL SHOW PROCESSLIST
<Id> root <Host> test Query <Time> NULL SHOW PROCESSLIST
......@@ -105,6 +105,30 @@ OPTIMIZE TABLE t1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
if (!$skip_update)
{
eval CREATE TABLE t1
(a INT NULL AUTO_INCREMENT,
UNIQUE KEY (a))
ENGINE=$engine;
SET LAST_INSERT_ID = 999;
SET INSERT_ID = 0;
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
SELECT * FROM t1;
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
SELECT * FROM t1;
UPDATE t1 SET a = 1 WHERE a IS NULL;
SELECT LAST_INSERT_ID();
SELECT * FROM t1;
UPDATE t1 SET a = NULL WHERE a = 1;
SELECT LAST_INSERT_ID();
SELECT * FROM t1;
DROP TABLE t1;
SET INSERT_ID = 1;
}
-- echo # Simple test with NULL
eval CREATE TABLE t1 (
c1 INT NOT NULL AUTO_INCREMENT,
......@@ -831,5 +855,30 @@ SELECT * FROM t ORDER BY c1 ASC;
DROP TABLE t;
if (!$skip_update)
{
eval CREATE TABLE t1
(a INT NULL AUTO_INCREMENT,
UNIQUE KEY (a))
ENGINE=$engine
PARTITION BY KEY(a) PARTITIONS 2;
SET LAST_INSERT_ID = 999;
SET INSERT_ID = 0;
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
SELECT * FROM t1;
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
SELECT * FROM t1;
UPDATE t1 SET a = 1 WHERE a IS NULL;
SELECT LAST_INSERT_ID();
SELECT * FROM t1;
UPDATE t1 SET a = NULL WHERE a = 1;
SELECT LAST_INSERT_ID();
SELECT * FROM t1;
DROP TABLE t1;
}
--echo ##############################################################################
}
......@@ -120,6 +120,38 @@ t1 CREATE TABLE `t1` (
PRIMARY KEY (`c1`)
) ENGINE=BLACKHOLE DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1
(a INT NULL AUTO_INCREMENT,
UNIQUE KEY (a))
ENGINE='Blackhole';
SET LAST_INSERT_ID = 999;
SET INSERT_ID = 0;
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
UPDATE t1 SET a = 1 WHERE a IS NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
UPDATE t1 SET a = NULL WHERE a = 1;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
DROP TABLE t1;
SET INSERT_ID = 1;
# Simple test with NULL
CREATE TABLE t1 (
c1 INT NOT NULL AUTO_INCREMENT,
......
......@@ -136,6 +136,42 @@ t1 CREATE TABLE `t1` (
PRIMARY KEY (`c1`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1
(a INT NULL AUTO_INCREMENT,
UNIQUE KEY (a))
ENGINE='InnoDB';
SET LAST_INSERT_ID = 999;
SET INSERT_ID = 0;
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
1
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
UPDATE t1 SET a = 1 WHERE a IS NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
UPDATE t1 SET a = NULL WHERE a = 1;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
DROP TABLE t1;
SET INSERT_ID = 1;
# Simple test with NULL
CREATE TABLE t1 (
c1 INT NOT NULL AUTO_INCREMENT,
......@@ -1023,4 +1059,40 @@ c1 c2
2 20
127 40
DROP TABLE t;
CREATE TABLE t1
(a INT NULL AUTO_INCREMENT,
UNIQUE KEY (a))
ENGINE='InnoDB'
PARTITION BY KEY(a) PARTITIONS 2;
SET LAST_INSERT_ID = 999;
SET INSERT_ID = 0;
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
1
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
UPDATE t1 SET a = 1 WHERE a IS NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
UPDATE t1 SET a = NULL WHERE a = 1;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
DROP TABLE t1;
##############################################################################
......@@ -136,6 +136,42 @@ t1 CREATE TABLE `t1` (
PRIMARY KEY (`c1`)
) ENGINE=MEMORY AUTO_INCREMENT=102 DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1
(a INT NULL AUTO_INCREMENT,
UNIQUE KEY (a))
ENGINE='Memory';
SET LAST_INSERT_ID = 999;
SET INSERT_ID = 0;
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
1
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
UPDATE t1 SET a = 1 WHERE a IS NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
UPDATE t1 SET a = NULL WHERE a = 1;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
DROP TABLE t1;
SET INSERT_ID = 1;
# Simple test with NULL
CREATE TABLE t1 (
c1 INT NOT NULL AUTO_INCREMENT,
......@@ -1051,4 +1087,40 @@ c1 c2
2 20
127 40
DROP TABLE t;
CREATE TABLE t1
(a INT NULL AUTO_INCREMENT,
UNIQUE KEY (a))
ENGINE='Memory'
PARTITION BY KEY(a) PARTITIONS 2;
SET LAST_INSERT_ID = 999;
SET INSERT_ID = 0;
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
1
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
UPDATE t1 SET a = 1 WHERE a IS NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
UPDATE t1 SET a = NULL WHERE a = 1;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
DROP TABLE t1;
##############################################################################
......@@ -136,6 +136,42 @@ t1 CREATE TABLE `t1` (
PRIMARY KEY (`c1`)
) ENGINE=MyISAM AUTO_INCREMENT=102 DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1
(a INT NULL AUTO_INCREMENT,
UNIQUE KEY (a))
ENGINE='MyISAM';
SET LAST_INSERT_ID = 999;
SET INSERT_ID = 0;
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
1
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
UPDATE t1 SET a = 1 WHERE a IS NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
UPDATE t1 SET a = NULL WHERE a = 1;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
DROP TABLE t1;
SET INSERT_ID = 1;
# Simple test with NULL
CREATE TABLE t1 (
c1 INT NOT NULL AUTO_INCREMENT,
......@@ -1070,4 +1106,40 @@ c1 c2
2 20
127 40
DROP TABLE t;
CREATE TABLE t1
(a INT NULL AUTO_INCREMENT,
UNIQUE KEY (a))
ENGINE='MyISAM'
PARTITION BY KEY(a) PARTITIONS 2;
SET LAST_INSERT_ID = 999;
SET INSERT_ID = 0;
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
1
INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
UPDATE t1 SET a = 1 WHERE a IS NULL;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
UPDATE t1 SET a = NULL WHERE a = 1;
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
999
SELECT * FROM t1;
a
0
DROP TABLE t1;
##############################################################################
......@@ -15,3 +15,8 @@ query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails spo
ctype_utf8mb4_ndb : Bug#55799, Bug#51907, disabled by Konstantin 2010-08-06
main.mysqlhotcopy_myisam : Bug#56817 2010-10-21 anitha mysqlhotcopy* fails
main.mysqlhotcopy_archive: Bug#56817 2010-10-21 anitha mysqlhotcopy* fails
log_tables-big : Bug#48646 2010-11-15 mattiasj report already exists
read_many_rows_innodb : Bug#37635 2010-11-15 mattiasj report already exists
sum_distinct-big : Bug#56927 2010-11-15 mattiasj was not tested
alter_table-big : Bug#37248 2010-11-15 mattiasj was not tested
create-big : Bug#37248 2010-11-15 mattiasj was not tested
......@@ -54,3 +54,57 @@ lock tables t1 read;
flush privileges;
unlock tables;
drop table t1;
--echo #
--echo # Bug#54812: assert in Diagnostics_area::set_ok_status during EXPLAIN
--echo #
CREATE USER nopriv_user@localhost;
connection default;
--echo connection: default
--disable_warnings
DROP TABLE IF EXISTS t1,t2,t3;
DROP FUNCTION IF EXISTS f;
--enable_warnings
CREATE TABLE t1 (key1 INT PRIMARY KEY);
CREATE TABLE t2 (key2 INT);
INSERT INTO t1 VALUES (1),(2);
CREATE FUNCTION f() RETURNS INT RETURN 1;
GRANT FILE ON *.* TO 'nopriv_user'@'localhost';
FLUSH PRIVILEGES;
connect (con1,localhost,nopriv_user,,);
connection con1;
--echo connection: con1
--error ER_PROCACCESS_DENIED_ERROR
SELECT MAX(key1) FROM t1 WHERE f() < 1 INTO OUTFILE 'mytest';
--error ER_PROCACCESS_DENIED_ERROR
INSERT INTO t2 SELECT MAX(key1) FROM t1 WHERE f() < 1;
--error ER_PROCACCESS_DENIED_ERROR
SELECT MAX(key1) INTO @dummy FROM t1 WHERE f() < 1;
--error ER_PROCACCESS_DENIED_ERROR
CREATE TABLE t3 (i INT) AS SELECT MAX(key1) FROM t1 WHERE f() < 1;
disconnect con1;
--source include/wait_until_disconnected.inc
connection default;
--echo connection: default
DROP TABLE t1,t2;
DROP FUNCTION f;
DROP USER nopriv_user@localhost;
--echo #
--echo # End Bug#54812
--echo #
......@@ -14,6 +14,24 @@
drop table if exists t1, t2;
--enable_warnings
--echo #
--echo # Bug#57778: failed primary key add to partitioned innodb table
--echo # inconsistent and crashes
--echo #
CREATE TABLE t1 (a INT NOT NULL, b INT NOT NULL)
PARTITION BY KEY (a) PARTITIONS 2;
INSERT INTO t1 VALUES (0,1), (0,2);
--error ER_DUP_ENTRY
ALTER TABLE t1 ADD PRIMARY KEY (a);
SHOW CREATE TABLE t1;
SELECT * FROM t1;
UPDATE t1 SET a = 1, b = 1 WHERE a = 0 AND b = 2;
ALTER TABLE t1 ADD PRIMARY KEY (a);
SELECT * FROM t1;
ALTER TABLE t1 DROP PRIMARY KEY;
SELECT * FROM t1;
DROP TABLE t1;
--echo #
--echo # Bug#57113: ha_partition::extra(ha_extra_function):
--echo # Assertion `m_extra_cache' failed
......
......@@ -37,19 +37,19 @@
--disable_warnings
SET SESSION transaction_prealloc_size=1024*1024*1024*1;
--replace_column 1 <Id> 6 <Time>
--replace_column 1 <Id> 3 <Host> 6 <Time>
SHOW PROCESSLIST;
SET SESSION transaction_prealloc_size=1024*1024*1024*2;
--replace_column 1 <Id> 6 <Time>
--replace_column 1 <Id> 3 <Host> 6 <Time>
SHOW PROCESSLIST;
SET SESSION transaction_prealloc_size=1024*1024*1024*3;
--replace_column 1 <Id> 6 <Time>
--replace_column 1 <Id> 3 <Host> 6 <Time>
SHOW PROCESSLIST;
SET SESSION transaction_prealloc_size=1024*1024*1024*4;
--replace_column 1 <Id> 6 <Time>
--replace_column 1 <Id> 3 <Host> 6 <Time>
SHOW PROCESSLIST;
SET SESSION transaction_prealloc_size=1024*1024*1024*5;
--replace_column 1 <Id> 6 <Time>
--replace_column 1 <Id> 3 <Host> 6 <Time>
SHOW PROCESSLIST;
--enable_warnings
......@@ -173,7 +173,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
if (file >= 0)
{
pos= my_tell(file, MYF(0));
pos= mysql_file_tell(file, MYF(0));
if ((pos == (my_off_t) -1) && (my_errno == ESPIPE))
{
/*
......@@ -205,7 +205,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
if (!(cache_myflags & MY_DONT_CHECK_FILESIZE))
{
/* Calculate end of file to avoid allocating oversized buffers */
end_of_file=my_seek(file,0L,MY_SEEK_END,MYF(0));
end_of_file= mysql_file_seek(file, 0L, MY_SEEK_END, MYF(0));
/* Need to reset seek_not_done now that we just did a seek. */
info->seek_not_done= end_of_file == seek_offset ? 0 : 1;
if (end_of_file < seek_offset)
......@@ -485,7 +485,7 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
*/
if (info->seek_not_done)
{
if ((my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0))
if ((mysql_file_seek(info->file, pos_in_file, MY_SEEK_SET, MYF(0))
!= MY_FILEPOS_ERROR))
{
/* No error, reset seek_not_done flag. */
......@@ -529,7 +529,7 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
end aligned with a block.
*/
length=(Count & (size_t) ~(IO_SIZE-1))-diff_length;
if ((read_length= my_read(info->file,Buffer, length, info->myflags))
if ((read_length= mysql_file_read(info->file,Buffer, length, info->myflags))
!= length)
{
/*
......@@ -572,7 +572,7 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
}
length=0; /* Didn't read any chars */
}
else if ((length= my_read(info->file,info->buffer, max_length,
else if ((length= mysql_file_read(info->file,info->buffer, max_length,
info->myflags)) < Count ||
length == (size_t) -1)
{
......@@ -1056,7 +1056,7 @@ int _my_b_read_r(register IO_CACHE *cache, uchar *Buffer, size_t Count)
*/
if (cache->seek_not_done)
{
if (my_seek(cache->file, pos_in_file, MY_SEEK_SET, MYF(0))
if (mysql_file_seek(cache->file, pos_in_file, MY_SEEK_SET, MYF(0))
== MY_FILEPOS_ERROR)
{
cache->error= -1;
......@@ -1064,7 +1064,7 @@ int _my_b_read_r(register IO_CACHE *cache, uchar *Buffer, size_t Count)
DBUG_RETURN(1);
}
}
len= my_read(cache->file, cache->buffer, length, cache->myflags);
len= mysql_file_read(cache->file, cache->buffer, length, cache->myflags);
}
DBUG_PRINT("io_cache_share", ("read %lu bytes", (ulong) len));
......@@ -1203,7 +1203,7 @@ int _my_b_seq_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
With read-append cache we must always do a seek before we read,
because the write could have moved the file pointer astray
*/
if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) == MY_FILEPOS_ERROR)
if (mysql_file_seek(info->file, pos_in_file, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR)
{
info->error= -1;
unlock_append_buffer(info);
......@@ -1220,8 +1220,8 @@ int _my_b_seq_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
size_t read_length;
length=(Count & (size_t) ~(IO_SIZE-1))-diff_length;
if ((read_length= my_read(info->file,Buffer, length,
info->myflags)) == (size_t) -1)
if ((read_length= mysql_file_read(info->file,Buffer, length,
info->myflags)) == (size_t) -1)
{
info->error= -1;
unlock_append_buffer(info);
......@@ -1254,7 +1254,7 @@ int _my_b_seq_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
}
else
{
length= my_read(info->file,info->buffer, max_length, info->myflags);
length= mysql_file_read(info->file,info->buffer, max_length, info->myflags);
if (length == (size_t) -1)
{
info->error= -1;
......@@ -1431,7 +1431,7 @@ int _my_b_async_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
return 1;
}
if (my_seek(info->file,next_pos_in_file,MY_SEEK_SET,MYF(0))
if (mysql_file_seek(info->file, next_pos_in_file, MY_SEEK_SET, MYF(0))
== MY_FILEPOS_ERROR)
{
info->error= -1;
......@@ -1441,8 +1441,8 @@ int _my_b_async_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
read_length=IO_SIZE*2- (size_t) (next_pos_in_file & (IO_SIZE-1));
if (Count < read_length)
{ /* Small block, read to cache */
if ((read_length=my_read(info->file,info->request_pos,
read_length, info->myflags)) == (size_t) -1)
if ((read_length=mysql_file_read(info->file,info->request_pos,
read_length, info->myflags)) == (size_t) -1)
return info->error= -1;
use_length=min(Count,read_length);
memcpy(Buffer,info->request_pos,(size_t) use_length);
......@@ -1462,7 +1462,7 @@ int _my_b_async_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
}
else
{ /* Big block, don't cache it */
if ((read_length= my_read(info->file,Buffer, Count,info->myflags))
if ((read_length= mysql_file_read(info->file, Buffer, Count,info->myflags))
!= Count)
{
info->error= read_length == (size_t) -1 ? -1 : read_length+left_length;
......@@ -1569,14 +1569,14 @@ int _my_b_write(register IO_CACHE *info, const uchar *Buffer, size_t Count)
"seek_not_done" to indicate this to other functions operating
on the IO_CACHE.
*/
if (my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0)))
if (mysql_file_seek(info->file, info->pos_in_file, MY_SEEK_SET, MYF(0)))
{
info->error= -1;
return (1);
}
info->seek_not_done=0;
}
if (my_write(info->file, Buffer, length, info->myflags | MY_NABP))
if (mysql_file_write(info->file, Buffer, length, info->myflags | MY_NABP))
return info->error= -1;
#ifdef THREAD
......@@ -1639,7 +1639,7 @@ int my_b_append(register IO_CACHE *info, const uchar *Buffer, size_t Count)
if (Count >= IO_SIZE)
{ /* Fill first intern buffer */
length=Count & (size_t) ~(IO_SIZE-1);
if (my_write(info->file,Buffer, length, info->myflags | MY_NABP))
if (mysql_file_write(info->file,Buffer, length, info->myflags | MY_NABP))
{
unlock_append_buffer(info);
return info->error= -1;
......@@ -1695,11 +1695,11 @@ int my_block_write(register IO_CACHE *info, const uchar *Buffer, size_t Count,
{
/* Of no overlap, write everything without buffering */
if (pos + Count <= info->pos_in_file)
return my_pwrite(info->file, Buffer, Count, pos,
info->myflags | MY_NABP);
return mysql_file_pwrite(info->file, Buffer, Count, pos,
info->myflags | MY_NABP);
/* Write the part of the block that is before buffer */
length= (uint) (info->pos_in_file - pos);
if (my_pwrite(info->file, Buffer, length, pos, info->myflags | MY_NABP))
if (mysql_file_pwrite(info->file, Buffer, length, pos, info->myflags | MY_NABP))
info->error= error= -1;
Buffer+=length;
pos+= length;
......@@ -1789,7 +1789,7 @@ int my_b_flush_io_cache(IO_CACHE *info,
*/
if (!append_cache && info->seek_not_done)
{ /* File touched, do seek */
if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) ==
if (mysql_file_seek(info->file, pos_in_file, MY_SEEK_SET, MYF(0)) ==
MY_FILEPOS_ERROR)
{
UNLOCK_APPEND_BUFFER;
......@@ -1803,7 +1803,7 @@ int my_b_flush_io_cache(IO_CACHE *info,
info->write_end= (info->write_buffer+info->buffer_length-
((pos_in_file+length) & (IO_SIZE-1)));
if (my_write(info->file,info->write_buffer,length,
if (mysql_file_write(info->file,info->write_buffer,length,
info->myflags | MY_NABP))
info->error= -1;
else
......@@ -1815,7 +1815,7 @@ int my_b_flush_io_cache(IO_CACHE *info,
else
{
info->end_of_file+=(info->write_pos-info->append_read_pos);
DBUG_ASSERT(info->end_of_file == my_tell(info->file,MYF(0)));
DBUG_ASSERT(info->end_of_file == mysql_file_tell(info->file, MYF(0)));
}
info->append_read_pos=info->write_pos=info->write_buffer;
......
......@@ -3093,7 +3093,9 @@ int ha_partition::write_row(uchar * buf)
bool have_auto_increment= table->next_number_field && buf == table->record[0];
my_bitmap_map *old_map;
THD *thd= ha_thd();
timestamp_auto_set_type orig_timestamp_type= table->timestamp_field_type;
timestamp_auto_set_type saved_timestamp_type= table->timestamp_field_type;
ulong saved_sql_mode= thd->variables.sql_mode;
bool saved_auto_inc_field_not_null= table->auto_increment_field_not_null;
#ifdef NOT_NEEDED
uchar *rec0= m_rec0;
#endif
......@@ -3129,6 +3131,22 @@ int ha_partition::write_row(uchar * buf)
*/
if (error)
goto exit;
/*
Don't allow generation of auto_increment value the partitions handler.
If a partitions handler would change the value, then it might not
match the partition any longer.
This can occur if 'SET INSERT_ID = 0; INSERT (NULL)',
So allow this by adding 'MODE_NO_AUTO_VALUE_ON_ZERO' to sql_mode.
The partitions handler::next_insert_id must always be 0. Otherwise
we need to forward release_auto_increment, or reset it for all
partitions.
*/
if (table->next_number_field->val_int() == 0)
{
table->auto_increment_field_not_null= TRUE;
thd->variables.sql_mode|= MODE_NO_AUTO_VALUE_ON_ZERO;
}
}
old_map= dbug_tmp_use_all_columns(table, table->read_set);
......@@ -3162,7 +3180,9 @@ int ha_partition::write_row(uchar * buf)
set_auto_increment_if_higher(table->next_number_field);
reenable_binlog(thd);
exit:
table->timestamp_field_type= orig_timestamp_type;
thd->variables.sql_mode= saved_sql_mode;
table->auto_increment_field_not_null= saved_auto_inc_field_not_null;
table->timestamp_field_type= saved_timestamp_type;
DBUG_RETURN(error);
}
......@@ -3229,11 +3249,24 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data)
}
else
{
Field *saved_next_number_field= table->next_number_field;
/*
Don't allow generation of auto_increment value for update.
table->next_number_field is never set on UPDATE.
But is set for INSERT ... ON DUPLICATE KEY UPDATE,
and since update_row() does not generate or update an auto_inc value,
we cannot have next_number_field set when moving a row
to another partition with write_row(), since that could
generate/update the auto_inc value.
This gives the same behavior for partitioned vs non partitioned tables.
*/
table->next_number_field= NULL;
DBUG_PRINT("info", ("Update from partition %d to partition %d",
old_part_id, new_part_id));
tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */
error= m_file[new_part_id]->ha_write_row(new_data);
reenable_binlog(thd);
table->next_number_field= saved_next_number_field;
if (error)
goto exit;
......@@ -6375,9 +6408,42 @@ bool ha_partition::get_error_message(int error, String *buf)
*/
uint ha_partition::alter_table_flags(uint flags)
{
uint flags_to_return, flags_to_check;
DBUG_ENTER("ha_partition::alter_table_flags");
DBUG_RETURN(ht->alter_table_flags(flags) |
m_file[0]->alter_table_flags(flags));
flags_to_return= ht->alter_table_flags(flags);
flags_to_return|= m_file[0]->alter_table_flags(flags);
/*
If one partition fails we must be able to revert the change for the other,
already altered, partitions. So both ADD and DROP can only be supported in
pairs.
*/
flags_to_check= HA_ONLINE_ADD_INDEX_NO_WRITES;
flags_to_check|= HA_ONLINE_DROP_INDEX_NO_WRITES;
if ((flags_to_return & flags_to_check) != flags_to_check)
flags_to_return&= ~flags_to_check;
flags_to_check= HA_ONLINE_ADD_UNIQUE_INDEX_NO_WRITES;
flags_to_check|= HA_ONLINE_DROP_UNIQUE_INDEX_NO_WRITES;
if ((flags_to_return & flags_to_check) != flags_to_check)
flags_to_return&= ~flags_to_check;
flags_to_check= HA_ONLINE_ADD_PK_INDEX_NO_WRITES;
flags_to_check|= HA_ONLINE_DROP_PK_INDEX_NO_WRITES;
if ((flags_to_return & flags_to_check) != flags_to_check)
flags_to_return&= ~flags_to_check;
flags_to_check= HA_ONLINE_ADD_INDEX;
flags_to_check|= HA_ONLINE_DROP_INDEX;
if ((flags_to_return & flags_to_check) != flags_to_check)
flags_to_return&= ~flags_to_check;
flags_to_check= HA_ONLINE_ADD_UNIQUE_INDEX;
flags_to_check|= HA_ONLINE_DROP_UNIQUE_INDEX;
if ((flags_to_return & flags_to_check) != flags_to_check)
flags_to_return&= ~flags_to_check;
flags_to_check= HA_ONLINE_ADD_PK_INDEX;
flags_to_check|= HA_ONLINE_DROP_PK_INDEX;
if ((flags_to_return & flags_to_check) != flags_to_check)
flags_to_return&= ~flags_to_check;
DBUG_RETURN(flags_to_return);
}
......@@ -6412,6 +6478,7 @@ int ha_partition::add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys)
handler **file;
int ret= 0;
DBUG_ENTER("ha_partition::add_index");
/*
There has already been a check in fix_partition_func in mysql_alter_table
before this call, which checks for unique/primary key violations of the
......@@ -6419,8 +6486,28 @@ int ha_partition::add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys)
*/
for (file= m_file; *file; file++)
if ((ret= (*file)->add_index(table_arg, key_info, num_of_keys)))
break;
return ret;
goto err;
DBUG_RETURN(ret);
err:
if (file > m_file)
{
uint *key_numbers= (uint*) ha_thd()->alloc(sizeof(uint) * num_of_keys);
uint old_num_of_keys= table_arg->s->keys;
uint i;
/* The newly created keys have the last id's */
for (i= 0; i < num_of_keys; i++)
key_numbers[i]= i + old_num_of_keys;
if (!table_arg->key_info)
table_arg->key_info= key_info;
while (--file >= m_file)
{
(void) (*file)->prepare_drop_index(table_arg, key_numbers, num_of_keys);
(void) (*file)->final_drop_index(table_arg);
}
if (table_arg->key_info == key_info)
table_arg->key_info= NULL;
}
DBUG_RETURN(ret);
}
......
......@@ -174,6 +174,8 @@
/*
These bits are set if different kinds of indexes can be created
off-line without re-create of the table (but with a table lock).
Partitioning needs both ADD and DROP to be supported by its underlying
handlers, due to error handling, see bug#57778.
*/
#define HA_ONLINE_ADD_INDEX_NO_WRITES (1L << 0) /*add index w/lock*/
#define HA_ONLINE_DROP_INDEX_NO_WRITES (1L << 1) /*drop index w/lock*/
......
......@@ -2177,7 +2177,11 @@ bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name,
1 error
*/
bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
bool MYSQL_LOG::open(
#ifdef HAVE_PSI_INTERFACE
PSI_file_key log_file_key,
#endif
const char *log_name, enum_log_type log_type_arg,
const char *new_name, enum cache_type io_cache_type_arg)
{
char buff[FN_REFLEN];
......@@ -2205,7 +2209,12 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
db[0]= 0;
if ((file= mysql_file_open(key_file_MYSQL_LOG,
#ifdef HAVE_PSI_INTERFACE
/* Keep the key for reopen */
m_log_file_key= log_file_key;
#endif
if ((file= mysql_file_open(log_file_key,
log_file_name, open_flags,
MYF(MY_WME | ME_WAITTANG))) < 0 ||
init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
......@@ -2389,7 +2398,11 @@ void MYSQL_QUERY_LOG::reopen_file()
Note that at this point, log_state != LOG_CLOSED (important for is_open()).
*/
open(save_name, log_type, 0, io_cache_type);
open(
#ifdef HAVE_PSI_INTERFACE
m_log_file_key,
#endif
save_name, log_type, 0, io_cache_type);
my_free(save_name);
mysql_mutex_unlock(&LOCK_log);
......@@ -2855,8 +2868,8 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
write_error= 0;
/* open the main log file */
if (MYSQL_LOG::open(log_name, log_type_arg, new_name,
io_cache_type_arg))
if (MYSQL_LOG::open(key_file_binlog,
log_name, log_type_arg, new_name, io_cache_type_arg))
{
#ifdef HAVE_REPLICATION
close_purge_index_file();
......
......@@ -196,7 +196,11 @@ class MYSQL_LOG
MYSQL_LOG();
void init_pthread_objects();
void cleanup();
bool open(const char *log_name,
bool open(
#ifdef HAVE_PSI_INTERFACE
PSI_file_key log_file_key,
#endif
const char *log_name,
enum_log_type log_type,
const char *new_name,
enum cache_type io_cache_type_arg);
......@@ -223,6 +227,10 @@ class MYSQL_LOG
volatile enum_log_state log_state;
enum cache_type io_cache_type;
friend class Log_event;
#ifdef HAVE_PSI_INTERFACE
/** Instrumentation key to use for file io in @c log_file */
PSI_file_key m_log_file_key;
#endif
};
class MYSQL_QUERY_LOG: public MYSQL_LOG
......@@ -241,14 +249,22 @@ class MYSQL_QUERY_LOG: public MYSQL_LOG
bool open_slow_log(const char *log_name)
{
char buf[FN_REFLEN];
return open(generate_name(log_name, "-slow.log", 0, buf), LOG_NORMAL, 0,
WRITE_CACHE);
return open(
#ifdef HAVE_PSI_INTERFACE
key_file_slow_log,
#endif
generate_name(log_name, "-slow.log", 0, buf),
LOG_NORMAL, 0, WRITE_CACHE);
}
bool open_query_log(const char *log_name)
{
char buf[FN_REFLEN];
return open(generate_name(log_name, ".log", 0, buf), LOG_NORMAL, 0,
WRITE_CACHE);
return open(
#ifdef HAVE_PSI_INTERFACE
key_file_query_log,
#endif
generate_name(log_name, ".log", 0, buf),
LOG_NORMAL, 0, WRITE_CACHE);
}
private:
......
......@@ -7838,9 +7838,10 @@ PSI_file_key key_file_binlog, key_file_binlog_index, key_file_casetest,
key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file,
key_file_fileparser, key_file_frm, key_file_global_ddl_log, key_file_load,
key_file_loadfile, key_file_log_event_data, key_file_log_event_info,
key_file_master_info, key_file_misc, key_file_MYSQL_LOG, key_file_partition,
key_file_master_info, key_file_misc, key_file_partition,
key_file_pid, key_file_relay_log_info, key_file_send_file, key_file_tclog,
key_file_trg, key_file_trn, key_file_init;
PSI_file_key key_file_query_log, key_file_slow_log;
static PSI_file_info all_server_files[]=
{
......@@ -7863,11 +7864,12 @@ static PSI_file_info all_server_files[]=
{ &key_file_log_event_info, "log_event_info", 0},
{ &key_file_master_info, "master_info", 0},
{ &key_file_misc, "misc", 0},
{ &key_file_MYSQL_LOG, "MYSQL_LOG", 0},
{ &key_file_partition, "partition", 0},
{ &key_file_pid, "pid", 0},
{ &key_file_query_log, "query_log", 0},
{ &key_file_relay_log_info, "relay_log_info", 0},
{ &key_file_send_file, "send_file", 0},
{ &key_file_slow_log, "slow_log", 0},
{ &key_file_tclog, "tclog", 0},
{ &key_file_trg, "trigger_name", 0},
{ &key_file_trn, "trigger", 0},
......
......@@ -270,9 +270,10 @@ extern PSI_file_key key_file_binlog, key_file_binlog_index, key_file_casetest,
key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file,
key_file_fileparser, key_file_frm, key_file_global_ddl_log, key_file_load,
key_file_loadfile, key_file_log_event_data, key_file_log_event_info,
key_file_master_info, key_file_misc, key_file_MYSQL_LOG, key_file_partition,
key_file_master_info, key_file_misc, key_file_partition,
key_file_pid, key_file_relay_log_info, key_file_send_file, key_file_tclog,
key_file_trg, key_file_trn, key_file_init;
extern PSI_file_key key_file_query_log, key_file_slow_log;
void init_server_psi_keys();
#endif /* HAVE_PSI_INTERFACE */
......
......@@ -1842,8 +1842,9 @@ void select_to_file::send_error(uint errcode,const char *err)
bool select_to_file::send_eof()
{
int error= test(end_io_cache(&cache));
if (mysql_file_close(file, MYF(MY_WME)))
error= 1;
if (mysql_file_close(file, MYF(MY_WME)) || thd->is_error())
error= true;
if (!error)
{
::my_ok(thd,row_count);
......@@ -2884,6 +2885,13 @@ bool select_dumpvar::send_eof()
if (! row_count)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA));
/*
Don't send EOF if we're in error condition (which implies we've already
sent or are sending an error)
*/
if (thd->is_error())
return true;
::my_ok(thd,row_count);
return 0;
}
......
......@@ -3506,6 +3506,9 @@ bool select_insert::send_eof()
error= (thd->locked_tables_mode <= LTM_LOCK_TABLES ?
table->file->ha_end_bulk_insert() : 0);
if (!error && thd->is_error())
error= thd->stmt_da->sql_errno();
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
......@@ -4049,7 +4052,7 @@ bool select_create::send_eof()
{
bool tmp=select_insert::send_eof();
if (tmp)
abort();
abort_result_set();
else
{
/*
......@@ -4081,7 +4084,7 @@ void select_create::abort_result_set()
DBUG_ENTER("select_create::abort_result_set");
/*
In select_insert::abort() we roll back the statement, including
In select_insert::abort_result_set() we roll back the statement, including
truncating the transaction cache of the binary log. To do this, we
pretend that the statement is transactional, even though it might
be the case that it was not.
......
......@@ -2898,8 +2898,15 @@ bool Select_fetch_protocol_binary::send_result_set_metadata(List<Item> &list, ui
bool Select_fetch_protocol_binary::send_eof()
{
/*
Don't send EOF if we're in error condition (which implies we've already
sent or are sending an error)
*/
if (thd->is_error())
return true;
::my_eof(thd);
return FALSE;
return false;
}
......
......@@ -2064,7 +2064,9 @@ bool multi_update::send_eof()
Does updates for the last n - 1 tables, returns 0 if ok;
error takes into account killed status gained in do_updates()
*/
int local_error = (table_count) ? do_updates() : 0;
int local_error= thd->is_error();
if (!local_error)
local_error = (table_count) ? do_updates() : 0;
/*
if local_error is not set ON until after do_updates() then
later carried out killing should not affect binlogging.
......
......@@ -79,5 +79,21 @@ inline uint randomized_index(const void *ptr, uint max_size)
void pfs_print_error(const char *format, ...);
/**
Given an array defined as T ARRAY[MAX],
check that an UNSAFE pointer actually points to an element
within the array.
*/
#define SANITIZE_ARRAY_BODY(T, ARRAY, MAX, UNSAFE) \
intptr offset; \
if ((&ARRAY[0] <= UNSAFE) && \
(UNSAFE < &ARRAY[MAX])) \
{ \
offset= ((intptr) UNSAFE - (intptr) ARRAY) % sizeof(T); \
if (offset == 0) \
return UNSAFE; \
} \
return NULL
#endif
......@@ -758,9 +758,26 @@ PFS_thread* create_thread(PFS_thread_class *klass, const void *identity,
*/
PFS_thread *sanitize_thread(PFS_thread *unsafe)
{
if ((&thread_array[0] <= unsafe) &&
(unsafe < &thread_array[thread_max]))
return unsafe;
SANITIZE_ARRAY_BODY(PFS_thread, thread_array, thread_max, unsafe);
}
const char *sanitize_file_name(const char *unsafe)
{
intptr ptr= (intptr) unsafe;
intptr first= (intptr) &file_array[0];
intptr last= (intptr) &file_array[file_max];
/* Check if unsafe points inside file_array[] */
if (likely((first <= ptr) && (ptr < last)))
{
/* Check if unsafe points to PFS_file::m_filename */
intptr offset= (ptr - first) % sizeof(PFS_file);
intptr valid_offset= my_offsetof(PFS_file, m_filename[0]);
if (likely(offset == valid_offset))
{
return unsafe;
}
}
return NULL;
}
......
......@@ -227,6 +227,7 @@ struct PFS_thread
};
PFS_thread *sanitize_thread(PFS_thread *unsafe);
const char *sanitize_file_name(const char *unsafe);
PFS_single_stat_chain*
find_per_thread_mutex_class_wait_stat(PFS_thread *thread,
......
......@@ -543,15 +543,9 @@ PFS_mutex_class *find_mutex_class(PFS_sync_key key)
FIND_CLASS_BODY(key, mutex_class_allocated_count, mutex_class_array);
}
#define SANITIZE_ARRAY_BODY(ARRAY, MAX, UNSAFE) \
if ((&ARRAY[0] <= UNSAFE) && \
(UNSAFE < &ARRAY[MAX])) \
return UNSAFE; \
return NULL
PFS_mutex_class *sanitize_mutex_class(PFS_mutex_class *unsafe)
{
SANITIZE_ARRAY_BODY(mutex_class_array, mutex_class_max, unsafe);
SANITIZE_ARRAY_BODY(PFS_mutex_class, mutex_class_array, mutex_class_max, unsafe);
}
/**
......@@ -566,7 +560,7 @@ PFS_rwlock_class *find_rwlock_class(PFS_sync_key key)
PFS_rwlock_class *sanitize_rwlock_class(PFS_rwlock_class *unsafe)
{
SANITIZE_ARRAY_BODY(rwlock_class_array, rwlock_class_max, unsafe);
SANITIZE_ARRAY_BODY(PFS_rwlock_class, rwlock_class_array, rwlock_class_max, unsafe);
}
/**
......@@ -581,7 +575,7 @@ PFS_cond_class *find_cond_class(PFS_sync_key key)
PFS_cond_class *sanitize_cond_class(PFS_cond_class *unsafe)
{
SANITIZE_ARRAY_BODY(cond_class_array, cond_class_max, unsafe);
SANITIZE_ARRAY_BODY(PFS_cond_class, cond_class_array, cond_class_max, unsafe);
}
/**
......@@ -636,7 +630,7 @@ PFS_thread_class *find_thread_class(PFS_sync_key key)
PFS_thread_class *sanitize_thread_class(PFS_thread_class *unsafe)
{
SANITIZE_ARRAY_BODY(thread_class_array, thread_class_max, unsafe);
SANITIZE_ARRAY_BODY(PFS_thread_class, thread_class_array, thread_class_max, unsafe);
}
/**
......@@ -687,7 +681,7 @@ PFS_file_class *find_file_class(PFS_file_key key)
PFS_file_class *sanitize_file_class(PFS_file_class *unsafe)
{
SANITIZE_ARRAY_BODY(file_class_array, file_class_max, unsafe);
SANITIZE_ARRAY_BODY(PFS_file_class, file_class_array, file_class_max, unsafe);
}
/**
......@@ -820,7 +814,59 @@ PFS_table_share* find_or_create_table_share(PFS_thread *thread,
PFS_table_share *sanitize_table_share(PFS_table_share *unsafe)
{
SANITIZE_ARRAY_BODY(table_share_array, table_share_max, unsafe);
SANITIZE_ARRAY_BODY(PFS_table_share, table_share_array, table_share_max, unsafe);
}
const char *sanitize_table_schema_name(const char *unsafe)
{
intptr ptr= (intptr) unsafe;
intptr first= (intptr) &table_share_array[0];
intptr last= (intptr) &table_share_array[table_share_max];
PFS_table_share dummy;
/* Check if unsafe points inside table_share_array[] */
if (likely((first <= ptr) && (ptr < last)))
{
intptr offset= (ptr - first) % sizeof(PFS_table_share);
intptr from= my_offsetof(PFS_table_share, m_key.m_hash_key);
intptr len= sizeof(dummy.m_key.m_hash_key);
/* Check if unsafe points inside PFS_table_share::m_key::m_hash_key */
if (likely((from <= offset) && (offset < from + len)))
{
PFS_table_share *base= (PFS_table_share*) (ptr - offset);
/* Check if unsafe really is the schema name */
if (likely(base->m_schema_name == unsafe))
return unsafe;
}
}
return NULL;
}
const char *sanitize_table_object_name(const char *unsafe)
{
intptr ptr= (intptr) unsafe;
intptr first= (intptr) &table_share_array[0];
intptr last= (intptr) &table_share_array[table_share_max];
PFS_table_share dummy;
/* Check if unsafe points inside table_share_array[] */
if (likely((first <= ptr) && (ptr < last)))
{
intptr offset= (ptr - first) % sizeof(PFS_table_share);
intptr from= my_offsetof(PFS_table_share, m_key.m_hash_key);
intptr len= sizeof(dummy.m_key.m_hash_key);
/* Check if unsafe points inside PFS_table_share::m_key::m_hash_key */
if (likely((from <= offset) && (offset < from + len)))
{
PFS_table_share *base= (PFS_table_share*) (ptr - offset);
/* Check if unsafe really is the table name */
if (likely(base->m_table_name == unsafe))
return unsafe;
}
}
return NULL;
}
static void reset_mutex_class_waits(void)
......
......@@ -222,6 +222,8 @@ PFS_thread_class *find_thread_class(PSI_thread_key key);
PFS_thread_class *sanitize_thread_class(PFS_thread_class *unsafe);
PFS_file_class *find_file_class(PSI_file_key key);
PFS_file_class *sanitize_file_class(PFS_file_class *unsafe);
const char *sanitize_table_schema_name(const char *unsafe);
const char *sanitize_table_object_name(const char *unsafe);
PFS_table_share *find_or_create_table_share(PFS_thread *thread,
const char *schema_name,
......
......@@ -194,6 +194,9 @@ void table_events_waits_common::make_row(bool thread_own_wait,
PFS_instr_class *safe_class;
const char *base;
const char *safe_source_file;
const char *safe_table_schema_name;
const char *safe_table_object_name;
const char *safe_file_name;
m_row_exists= false;
safe_thread= sanitize_thread(pfs_thread);
......@@ -252,15 +255,19 @@ void table_events_waits_common::make_row(bool thread_own_wait,
m_row.m_object_type= "TABLE";
m_row.m_object_type_length= 5;
m_row.m_object_schema_length= wait->m_schema_name_length;
safe_table_schema_name= sanitize_table_schema_name(wait->m_schema_name);
if (unlikely((m_row.m_object_schema_length == 0) ||
(m_row.m_object_schema_length > sizeof(m_row.m_object_schema))))
(m_row.m_object_schema_length > sizeof(m_row.m_object_schema)) ||
(safe_table_schema_name == NULL)))
return;
memcpy(m_row.m_object_schema, wait->m_schema_name, m_row.m_object_schema_length);
memcpy(m_row.m_object_schema, safe_table_schema_name, m_row.m_object_schema_length);
m_row.m_object_name_length= wait->m_object_name_length;
safe_table_object_name= sanitize_table_object_name(wait->m_object_name);
if (unlikely((m_row.m_object_name_length == 0) ||
(m_row.m_object_name_length > sizeof(m_row.m_object_name))))
(m_row.m_object_name_length > sizeof(m_row.m_object_name)) ||
(safe_table_object_name == NULL)))
return;
memcpy(m_row.m_object_name, wait->m_object_name, m_row.m_object_name_length);
memcpy(m_row.m_object_name, safe_table_object_name, m_row.m_object_name_length);
safe_class= &global_table_class;
break;
case WAIT_CLASS_FILE:
......@@ -268,10 +275,12 @@ void table_events_waits_common::make_row(bool thread_own_wait,
m_row.m_object_type_length= 4;
m_row.m_object_schema_length= 0;
m_row.m_object_name_length= wait->m_object_name_length;
safe_file_name= sanitize_file_name(wait->m_object_name);
if (unlikely((m_row.m_object_name_length == 0) ||
(m_row.m_object_name_length > sizeof(m_row.m_object_name))))
(m_row.m_object_name_length > sizeof(m_row.m_object_name)) ||
(safe_file_name == NULL)))
return;
memcpy(m_row.m_object_name, wait->m_object_name, m_row.m_object_name_length);
memcpy(m_row.m_object_name, safe_file_name, m_row.m_object_name_length);
safe_class= sanitize_file_class((PFS_file_class*) wait->m_class);
break;
case NO_WAIT_CLASS:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment