merge 5.1->5.1-security.

This commit is contained in:
Georgi Kodinov 2011-12-12 12:25:35 +01:00
commit ba788ec90e
43 changed files with 1555 additions and 329 deletions

View File

@ -57,7 +57,7 @@ LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file)
char *batch_readline(LINE_BUFFER *line_buff)
{
char *pos;
ulong out_length;
ulong out_length= 0;
if (!(pos=intern_read_line(line_buff, &out_length)))
return 0;

View File

@ -43,7 +43,12 @@
#define LIBEDIT_MAJOR 2
#define LIBEDIT_MINOR 11
/* XXXMYSQL : stdint.h might not be available on older Solaris platforms. */
#if defined(__sun) || defined(__sun__)
#include <sys/inttypes.h>
#else
#include <stdint.h>
#endif
#include <sys/types.h>
#include <stdio.h>

View File

@ -47,14 +47,21 @@ static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93";
#include <assert.h>
#include <ctype.h>
/* XXXMYSQL : stdint.h might not be available on older Solaris platforms. */
#if defined(__sun) || defined(__sun__)
#include <sys/inttypes.h>
#else
#include <stdint.h>
#endif
#include <stdio.h>
#include <errno.h>
#ifdef HAVE_VIS_H
#include <vis.h>
#else
/*
XXXMYSQL : Due to different versions of vis.h available,
use the one bundled with libedit.
*/
#include "np/vis.h"
#endif
#ifdef __weak_alias
__weak_alias(strnunvisx,_strnunvisx)

View File

@ -68,11 +68,11 @@
#include <sys/types.h>
#include <assert.h>
#ifdef HAVE_VIS_H
#include <vis.h>
#else
/*
XXXMYSQL : Due to different versions of vis.h available,
use the one bundled with libedit.
*/
#include "np/vis.h"
#endif
#include <errno.h>
#include <stdlib.h>

View File

@ -333,7 +333,7 @@ memset(&state, 0, sizeof(mbstate_t));
#ifdef WIDECHAR
++cbp;
if (cbp > MB_CUR_MAX) { /* "shouldn't happen" */
if (cbp > (size_t) MB_CUR_MAX) { /* "shouldn't happen" */
*cp = '\0';
return (-1);
}

View File

@ -1,5 +1,4 @@
/*
Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -12,8 +11,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifndef _my_stacktrace_h_
#define _my_stacktrace_h_
@ -63,6 +61,69 @@ void my_set_exception_pointers(EXCEPTION_POINTERS *ep);
void my_write_core(int sig);
#endif
/**
Async-signal-safe utility functions used by signal handler routines.
Declared here in order to unit-test them.
These are not general-purpose, but tailored to the signal handling routines.
*/
/**
Converts a longlong value to string.
@param base 10 for decimal, 16 for hex values (0..9a..f)
@param val The value to convert
@param buf Assumed to point to the *end* of the buffer.
@returns Pointer to the first character of the converted string.
Negative values:
for base-10 the return string will be prepended with '-'
for base-16 the return string will contain 16 characters
Implemented with simplicity, and async-signal-safety in mind.
*/
char *my_safe_itoa(int base, longlong val, char *buf);
/**
Converts a ulonglong value to string.
@param base 10 for decimal, 16 for hex values (0..9a..f)
@param val The value to convert
@param buf Assumed to point to the *end* of the buffer.
@returns Pointer to the first character of the converted string.
Implemented with simplicity, and async-signal-safety in mind.
*/
char *my_safe_utoa(int base, ulonglong val, char *buf);
/**
A (very) limited version of snprintf.
@param to Destination buffer.
@param n Size of destination buffer.
@param fmt printf() style format string.
@returns Number of bytes written, including terminating '\0'
Supports 'd' 'i' 'u' 'x' 'p' 's' conversion.
Supports 'l' and 'll' modifiers for integral types.
Does not support any width/precision.
Implemented with simplicity, and async-signal-safety in mind.
*/
size_t my_safe_snprintf(char* to, size_t n, const char* fmt, ...)
ATTRIBUTE_FORMAT(printf, 3, 4);
/**
A (very) limited version of snprintf, which writes the result to STDERR.
@sa my_safe_snprintf
Implemented with simplicity, and async-signal-safety in mind.
@note Has an internal buffer capacity of 512 bytes,
which should suffice for our signal handling routines.
*/
size_t my_safe_printf_stderr(const char* fmt, ...)
ATTRIBUTE_FORMAT(printf, 1, 2);
/**
Writes up to count bytes from buffer to STDERR.
Implemented with simplicity, and async-signal-safety in mind.
@param buf Buffer containing data to be written.
@param count Number of bytes to write.
@returns Number of bytes written.
*/
size_t my_write_stderr(const void *buf, size_t count);
C_MODE_END
#endif /* _my_stacktrace_h_ */

View File

@ -109,6 +109,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/password.c ../sql/discover.cc ../sql/derror.cc
../sql/field.cc ../sql/field_conv.cc
../sql/filesort.cc ../sql/gstream.cc ../sql/ha_partition.cc
../sql/signal_handler.cc
../sql/handler.cc ../sql/hash_filo.cc ../sql/hostname.cc
../sql/init.cc ../sql/item_buff.cc ../sql/item_cmpfunc.cc
../sql/item.cc ../sql/item_create.cc ../sql/item_func.cc

View File

@ -12772,3 +12772,22 @@ a b c d e f
-1 b c d e 1
DROP TABLE t1;
SET sort_buffer_size=DEFAULT;
#
# BUG#11758979 - 51252: ARCHIVE TABLES CAUSE 100% CPU USAGE
# AND HANG IN SHOW TABLE STATUS
# (to be executed with valgrind)
CREATE TABLE t1(a BLOB, b VARCHAR(200)) ENGINE=ARCHIVE;
INSERT INTO t1 VALUES(NULL, '');
FLUSH TABLE t1;
# we need this select to workaround BUG#11764364
SELECT * FROM t1;
a b
NULL
CHECKSUM TABLE t1 EXTENDED;
Table Checksum
test.t1 286155052
FLUSH TABLE t1;
OPTIMIZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 optimize status OK
DROP TABLE t1;

View File

@ -55,3 +55,20 @@ id x
1 1
2 10
drop table t1;
#
#Bug#12842206 INNODB LOCKING REGRESSION FOR INSERT IGNORE
#fixed by re-fixing Bug#7975
#aka Bug#11759688 52020: InnoDB can still deadlock on just INSERT...
#
CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB;
INSERT INTO t1 VALUES(3,1);
BEGIN;
INSERT IGNORE INTO t1 VALUES(3,14);
BEGIN;
INSERT IGNORE INTO t1 VALUES(3,23);
SELECT * FROM t1 FOR UPDATE;
COMMIT;
a b
3 1
COMMIT;
DROP TABLE t1;

View File

@ -0,0 +1,77 @@
#
#Bug#11759688 52020: InnoDB can still deadlock
#on just INSERT...ON DUPLICATE KEY
#a.k.a. Bug#7975 deadlock without any locking, simple select and update
#
CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB;
INSERT INTO t1 VALUES(3,1);
BEGIN;
SET DEBUG_SYNC='write_row_noreplace SIGNAL insert1 WAIT_FOR select1';
INSERT INTO t1 VALUES(3,2);
SET DEBUG_SYNC='now WAIT_FOR insert1';
SELECT * FROM t1 LOCK IN SHARE MODE;
a b
3 1
SELECT * FROM t1 FOR UPDATE;
SET DEBUG_SYNC='now SIGNAL select1';
ERROR 23000: Duplicate entry '3' for key 'PRIMARY'
INSERT INTO t1 VALUES(3,3) ON DUPLICATE KEY UPDATE b=b+10;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
COMMIT;
SET DEBUG_SYNC='write_row_replace SIGNAL insert2 WAIT_FOR select2';
REPLACE INTO t1 VALUES(3,4);
SET DEBUG_SYNC='now WAIT_FOR insert2';
SELECT * FROM t1;
a b
3 11
SELECT * FROM t1 LOCK IN SHARE MODE;
SET DEBUG_SYNC='now SIGNAL select2';
SET DEBUG_SYNC='write_row_replace SIGNAL insert3 WAIT_FOR select3';
INSERT INTO t1 VALUES(3,5) ON DUPLICATE KEY UPDATE b=b+20;
a b
3 4
SET DEBUG_SYNC='now WAIT_FOR insert3';
SELECT b FROM t1 LOCK IN SHARE MODE;
SET DEBUG_SYNC='now SIGNAL select3';
b
24
SET DEBUG_SYNC='write_row_noreplace SIGNAL insert4 WAIT_FOR select4';
LOAD DATA INFILE '../../std_data/loaddata5.dat' INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b);
SET DEBUG_SYNC='now WAIT_FOR insert4';
SELECT b FROM t1 WHERE a=3 LOCK IN SHARE MODE;
b
24
SELECT b FROM t1 WHERE a=3 FOR UPDATE;
SET DEBUG_SYNC='now SIGNAL select4';
b
24
ERROR 23000: Duplicate entry '3' for key 'PRIMARY'
SET DEBUG_SYNC='write_row_noreplace SIGNAL insert5 WAIT_FOR select5';
LOAD DATA INFILE '../../std_data/loaddata5.dat' IGNORE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b);
SET DEBUG_SYNC='now WAIT_FOR insert5';
SELECT * FROM t1;
a b
3 24
SELECT * FROM t1 WHERE a=3 LOCK IN SHARE MODE;
a b
3 24
SELECT * FROM t1 WHERE a=3 FOR UPDATE;
SET DEBUG_SYNC='now SIGNAL select5';
a b
3 24
SET DEBUG_SYNC='write_row_replace SIGNAL insert6 WAIT_FOR select6';
LOAD DATA INFILE '../../std_data/loaddata5.dat' REPLACE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b);
SET DEBUG_SYNC='now WAIT_FOR insert6';
SELECT * FROM t1;
a b
1 2
3 24
5 6
SELECT a,b FROM t1 LOCK IN SHARE MODE;
SET DEBUG_SYNC='now SIGNAL select6';
a b
1 2
3 4
5 6
SET DEBUG_SYNC='RESET';
DROP TABLE t1;

View File

@ -100,3 +100,44 @@ select * from t1;
drop table t1;
# End of 4.1 tests
--echo #
--echo #Bug#12842206 INNODB LOCKING REGRESSION FOR INSERT IGNORE
--echo #fixed by re-fixing Bug#7975
--echo #aka Bug#11759688 52020: InnoDB can still deadlock on just INSERT...
--echo #
connection default;
CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB;
INSERT INTO t1 VALUES(3,1);
BEGIN;
# this used to wrongly acquire an X lock; now it takes an S lock
INSERT IGNORE INTO t1 VALUES(3,14);
connection con1;
BEGIN;
# this used to wrongly acquire an X lock; now it takes an S lock
INSERT IGNORE INTO t1 VALUES(3,23);
--send
SELECT * FROM t1 FOR UPDATE;
connection con2;
# Check that the above SELECT is blocked
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = 'Sending data' and
info = 'SELECT * FROM t1 FOR UPDATE';
--source include/wait_condition.inc
connection default;
COMMIT;
connection con1;
reap;
COMMIT;
disconnect con1;
disconnect con2;
connection default;
DROP TABLE t1;

View File

@ -0,0 +1,186 @@
--source include/have_innodb.inc
--source include/have_debug_sync.inc
--echo #
--echo #Bug#11759688 52020: InnoDB can still deadlock
--echo #on just INSERT...ON DUPLICATE KEY
--echo #a.k.a. Bug#7975 deadlock without any locking, simple select and update
--echo #
CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB;
INSERT INTO t1 VALUES(3,1);
connect (con1,localhost,root,,);
connect (con2,localhost,root,,);
connection con1;
BEGIN;
# normal INSERT of a duplicate should only S-lock the existing record (3,1)
SET DEBUG_SYNC='write_row_noreplace SIGNAL insert1 WAIT_FOR select1';
--send
INSERT INTO t1 VALUES(3,2);
connection default;
SET DEBUG_SYNC='now WAIT_FOR insert1';
# this should S-lock (3,1); no conflict
SELECT * FROM t1 LOCK IN SHARE MODE;
# this should X-lock (3,1), conflicting with con1
--send
SELECT * FROM t1 FOR UPDATE;
connection con2;
# Check that the above SELECT is blocked
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = 'Sending data' and
info = 'SELECT * FROM t1 FOR UPDATE';
--source include/wait_condition.inc
SET DEBUG_SYNC='now SIGNAL select1';
connection con1;
--error ER_DUP_ENTRY
reap;
# We are still holding an S-lock on (3,1) after the failed INSERT.
# The following will upgrade it to an X-lock, causing a deadlock.
# InnoDB should resolve the deadlock by aborting the blocked SELECT.
INSERT INTO t1 VALUES(3,3) ON DUPLICATE KEY UPDATE b=b+10;
connection default;
--error ER_LOCK_DEADLOCK
reap;
connection con1;
COMMIT;
SET DEBUG_SYNC='write_row_replace SIGNAL insert2 WAIT_FOR select2';
--send
REPLACE INTO t1 VALUES(3,4);
connection default;
SET DEBUG_SYNC='now WAIT_FOR insert2';
SELECT * FROM t1;
--send
SELECT * FROM t1 LOCK IN SHARE MODE;
connection con2;
# Check that the above SELECT is blocked because of X lock.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = 'Sending data' and
info = 'SELECT * FROM t1 LOCK IN SHARE MODE';
--source include/wait_condition.inc
SET DEBUG_SYNC='now SIGNAL select2';
connection con1;
reap;
SET DEBUG_SYNC='write_row_replace SIGNAL insert3 WAIT_FOR select3';
--send
INSERT INTO t1 VALUES(3,5) ON DUPLICATE KEY UPDATE b=b+20;
connection default;
reap;
SET DEBUG_SYNC='now WAIT_FOR insert3';
--send
SELECT b FROM t1 LOCK IN SHARE MODE;
connection con2;
# Check that the above SELECT is blocked because of X lock.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = 'Sending data' and
info = 'SELECT b FROM t1 LOCK IN SHARE MODE';
--source include/wait_condition.inc
SET DEBUG_SYNC='now SIGNAL select3';
connection default;
reap;
connection con1;
reap;
SET DEBUG_SYNC='write_row_noreplace SIGNAL insert4 WAIT_FOR select4';
--send
LOAD DATA INFILE '../../std_data/loaddata5.dat' INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b);
connection default;
SET DEBUG_SYNC='now WAIT_FOR insert4';
# this should S-lock (3,1); no conflict
SELECT b FROM t1 WHERE a=3 LOCK IN SHARE MODE;
# this should X-lock (3,1), conflicting with con1
--send
SELECT b FROM t1 WHERE a=3 FOR UPDATE;
connection con2;
# Check that the above SELECT is blocked
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = 'statistics' and
info = 'SELECT b FROM t1 WHERE a=3 FOR UPDATE';
--source include/wait_condition.inc
SET DEBUG_SYNC='now SIGNAL select4';
connection default;
reap;
connection con1;
--error ER_DUP_ENTRY
reap;
SET DEBUG_SYNC='write_row_noreplace SIGNAL insert5 WAIT_FOR select5';
--send
LOAD DATA INFILE '../../std_data/loaddata5.dat' IGNORE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b);
connection default;
SET DEBUG_SYNC='now WAIT_FOR insert5';
SELECT * FROM t1;
# this should S-lock; no conflict
SELECT * FROM t1 WHERE a=3 LOCK IN SHARE MODE;
# this should X-lock, conflicting with the S-lock of the IGNORE in con1
--send
SELECT * FROM t1 WHERE a=3 FOR UPDATE;
connection con2;
# Check that the above SELECT is blocked
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = 'statistics' and
info = 'SELECT * FROM t1 WHERE a=3 FOR UPDATE';
--source include/wait_condition.inc
SET DEBUG_SYNC='now SIGNAL select5';
connection con1;
reap;
connection default;
reap;
connection con1;
SET DEBUG_SYNC='write_row_replace SIGNAL insert6 WAIT_FOR select6';
--send
LOAD DATA INFILE '../../std_data/loaddata5.dat' REPLACE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b);
connection default;
SET DEBUG_SYNC='now WAIT_FOR insert6';
SELECT * FROM t1;
# this should conflict with the X-lock acquired by the REPLACE
--send
SELECT a,b FROM t1 LOCK IN SHARE MODE;
connection con2;
# Check that the above SELECT is blocked
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = 'Sending data' and
info = 'SELECT a,b FROM t1 LOCK IN SHARE MODE';
--source include/wait_condition.inc
SET DEBUG_SYNC='now SIGNAL select6';
connection con1;
reap;
connection default;
reap;
disconnect con1;
disconnect con2;
connection default;
SET DEBUG_SYNC='RESET';
DROP TABLE t1;

View File

@ -55,3 +55,20 @@ id x
1 1
2 10
drop table t1;
#
#Bug#12842206 INNODB LOCKING REGRESSION FOR INSERT IGNORE
#fixed by re-fixing Bug#7975
#aka Bug#11759688 52020: InnoDB can still deadlock on just INSERT...
#
CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB;
INSERT INTO t1 VALUES(3,1);
BEGIN;
INSERT IGNORE INTO t1 VALUES(3,14);
BEGIN;
INSERT IGNORE INTO t1 VALUES(3,23);
SELECT * FROM t1 FOR UPDATE;
COMMIT;
a b
3 1
COMMIT;
DROP TABLE t1;

View File

@ -0,0 +1,13 @@
set global innodb_file_per_table=on;
set global innodb_file_format=`1`;
create table t1(a text) engine=innodb key_block_size=8;
SELECT page_size FROM information_schema.innodb_cmpmem WHERE pages_used > 0;
page_size
8192
drop table t1;
SELECT page_size FROM information_schema.innodb_cmpmem WHERE pages_used > 0;
page_size
create table t2(a text) engine=innodb;
SELECT page_size FROM information_schema.innodb_cmpmem WHERE pages_used > 0;
page_size
drop table t2;

View File

@ -0,0 +1,77 @@
#
#Bug#11759688 52020: InnoDB can still deadlock
#on just INSERT...ON DUPLICATE KEY
#a.k.a. Bug#7975 deadlock without any locking, simple select and update
#
CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB;
INSERT INTO t1 VALUES(3,1);
BEGIN;
SET DEBUG_SYNC='write_row_noreplace SIGNAL insert1 WAIT_FOR select1';
INSERT INTO t1 VALUES(3,2);
SET DEBUG_SYNC='now WAIT_FOR insert1';
SELECT * FROM t1 LOCK IN SHARE MODE;
a b
3 1
SELECT * FROM t1 FOR UPDATE;
SET DEBUG_SYNC='now SIGNAL select1';
ERROR 23000: Duplicate entry '3' for key 'PRIMARY'
INSERT INTO t1 VALUES(3,3) ON DUPLICATE KEY UPDATE b=b+10;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
COMMIT;
SET DEBUG_SYNC='write_row_replace SIGNAL insert2 WAIT_FOR select2';
REPLACE INTO t1 VALUES(3,4);
SET DEBUG_SYNC='now WAIT_FOR insert2';
SELECT * FROM t1;
a b
3 11
SELECT * FROM t1 LOCK IN SHARE MODE;
SET DEBUG_SYNC='now SIGNAL select2';
SET DEBUG_SYNC='write_row_replace SIGNAL insert3 WAIT_FOR select3';
INSERT INTO t1 VALUES(3,5) ON DUPLICATE KEY UPDATE b=b+20;
a b
3 4
SET DEBUG_SYNC='now WAIT_FOR insert3';
SELECT b FROM t1 LOCK IN SHARE MODE;
SET DEBUG_SYNC='now SIGNAL select3';
b
24
SET DEBUG_SYNC='write_row_noreplace SIGNAL insert4 WAIT_FOR select4';
LOAD DATA INFILE '../../std_data/loaddata5.dat' INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b);
SET DEBUG_SYNC='now WAIT_FOR insert4';
SELECT b FROM t1 WHERE a=3 LOCK IN SHARE MODE;
b
24
SELECT b FROM t1 WHERE a=3 FOR UPDATE;
SET DEBUG_SYNC='now SIGNAL select4';
b
24
ERROR 23000: Duplicate entry '3' for key 'PRIMARY'
SET DEBUG_SYNC='write_row_noreplace SIGNAL insert5 WAIT_FOR select5';
LOAD DATA INFILE '../../std_data/loaddata5.dat' IGNORE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b);
SET DEBUG_SYNC='now WAIT_FOR insert5';
SELECT * FROM t1;
a b
3 24
SELECT * FROM t1 WHERE a=3 LOCK IN SHARE MODE;
a b
3 24
SELECT * FROM t1 WHERE a=3 FOR UPDATE;
SET DEBUG_SYNC='now SIGNAL select5';
a b
3 24
SET DEBUG_SYNC='write_row_replace SIGNAL insert6 WAIT_FOR select6';
LOAD DATA INFILE '../../std_data/loaddata5.dat' REPLACE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b);
SET DEBUG_SYNC='now WAIT_FOR insert6';
SELECT * FROM t1;
a b
1 2
3 24
5 6
SELECT a,b FROM t1 LOCK IN SHARE MODE;
SET DEBUG_SYNC='now SIGNAL select6';
a b
1 2
3 4
5 6
SET DEBUG_SYNC='RESET';
DROP TABLE t1;

View File

@ -100,3 +100,44 @@ select * from t1;
drop table t1;
# End of 4.1 tests
--echo #
--echo #Bug#12842206 INNODB LOCKING REGRESSION FOR INSERT IGNORE
--echo #fixed by re-fixing Bug#7975
--echo #aka Bug#11759688 52020: InnoDB can still deadlock on just INSERT...
--echo #
connection default;
CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB;
INSERT INTO t1 VALUES(3,1);
BEGIN;
# this used to wrongly acquire an X lock; now it takes an S lock
INSERT IGNORE INTO t1 VALUES(3,14);
connection con1;
BEGIN;
# this used to wrongly acquire an X lock; now it takes an S lock
INSERT IGNORE INTO t1 VALUES(3,23);
--send
SELECT * FROM t1 FOR UPDATE;
connection con2;
# Check that the above SELECT is blocked
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = 'Sending data' and
info = 'SELECT * FROM t1 FOR UPDATE';
--source include/wait_condition.inc
connection default;
COMMIT;
connection con1;
reap;
COMMIT;
disconnect con1;
disconnect con2;
connection default;
DROP TABLE t1;

View File

@ -0,0 +1 @@
--innodb-buffer-pool-size=8M

View File

@ -0,0 +1,59 @@
-- source include/have_innodb_plugin.inc
let $per_table=`select @@innodb_file_per_table`;
let $format=`select @@innodb_file_format`;
-- let $query_i_s = SELECT page_size FROM information_schema.innodb_cmpmem WHERE pages_used > 0
set global innodb_file_per_table=on;
set global innodb_file_format=`1`;
create table t1(a text) engine=innodb key_block_size=8;
-- disable_query_log
# insert some rows so we are using compressed pages
-- let $i = 10
while ($i)
{
insert into t1 values(repeat('abcdefghijklmnopqrstuvwxyz',100));
dec $i;
}
-- enable_query_log
# we should be using some 8K pages
-- eval $query_i_s
drop table t1;
# no lazy eviction at drop table in 5.1 there should still be no
# used 8K pages
-- eval $query_i_s
# create a non-compressed table and insert enough into it to evict
# compressed pages
create table t2(a text) engine=innodb;
-- disable_query_log
-- let $i = 200
while ($i)
{
insert into t2 values(repeat('abcdefghijklmnopqrstuvwxyz',1000));
dec $i;
}
-- enable_query_log
# now there should be no 8K pages in the buffer pool
-- eval $query_i_s
drop table t2;
#
# restore environment to the state it was before this test execution
#
-- disable_query_log
eval set global innodb_file_format=$format;
eval set global innodb_file_per_table=$per_table;

View File

@ -0,0 +1,186 @@
--source include/have_innodb_plugin.inc
--source include/have_debug_sync.inc
--echo #
--echo #Bug#11759688 52020: InnoDB can still deadlock
--echo #on just INSERT...ON DUPLICATE KEY
--echo #a.k.a. Bug#7975 deadlock without any locking, simple select and update
--echo #
CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB;
INSERT INTO t1 VALUES(3,1);
connect (con1,localhost,root,,);
connect (con2,localhost,root,,);
connection con1;
BEGIN;
# normal INSERT of a duplicate should only S-lock the existing record (3,1)
SET DEBUG_SYNC='write_row_noreplace SIGNAL insert1 WAIT_FOR select1';
--send
INSERT INTO t1 VALUES(3,2);
connection default;
SET DEBUG_SYNC='now WAIT_FOR insert1';
# this should S-lock (3,1); no conflict
SELECT * FROM t1 LOCK IN SHARE MODE;
# this should X-lock (3,1), conflicting with con1
--send
SELECT * FROM t1 FOR UPDATE;
connection con2;
# Check that the above SELECT is blocked
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = 'Sending data' and
info = 'SELECT * FROM t1 FOR UPDATE';
--source include/wait_condition.inc
SET DEBUG_SYNC='now SIGNAL select1';
connection con1;
--error ER_DUP_ENTRY
reap;
# We are still holding an S-lock on (3,1) after the failed INSERT.
# The following will upgrade it to an X-lock, causing a deadlock.
# InnoDB should resolve the deadlock by aborting the blocked SELECT.
INSERT INTO t1 VALUES(3,3) ON DUPLICATE KEY UPDATE b=b+10;
connection default;
--error ER_LOCK_DEADLOCK
reap;
connection con1;
COMMIT;
SET DEBUG_SYNC='write_row_replace SIGNAL insert2 WAIT_FOR select2';
--send
REPLACE INTO t1 VALUES(3,4);
connection default;
SET DEBUG_SYNC='now WAIT_FOR insert2';
SELECT * FROM t1;
--send
SELECT * FROM t1 LOCK IN SHARE MODE;
connection con2;
# Check that the above SELECT is blocked because of X lock.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = 'Sending data' and
info = 'SELECT * FROM t1 LOCK IN SHARE MODE';
--source include/wait_condition.inc
SET DEBUG_SYNC='now SIGNAL select2';
connection con1;
reap;
SET DEBUG_SYNC='write_row_replace SIGNAL insert3 WAIT_FOR select3';
--send
INSERT INTO t1 VALUES(3,5) ON DUPLICATE KEY UPDATE b=b+20;
connection default;
reap;
SET DEBUG_SYNC='now WAIT_FOR insert3';
--send
SELECT b FROM t1 LOCK IN SHARE MODE;
connection con2;
# Check that the above SELECT is blocked because of X lock.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = 'Sending data' and
info = 'SELECT b FROM t1 LOCK IN SHARE MODE';
--source include/wait_condition.inc
SET DEBUG_SYNC='now SIGNAL select3';
connection default;
reap;
connection con1;
reap;
SET DEBUG_SYNC='write_row_noreplace SIGNAL insert4 WAIT_FOR select4';
--send
LOAD DATA INFILE '../../std_data/loaddata5.dat' INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b);
connection default;
SET DEBUG_SYNC='now WAIT_FOR insert4';
# this should S-lock (3,1); no conflict
SELECT b FROM t1 WHERE a=3 LOCK IN SHARE MODE;
# this should X-lock (3,1), conflicting with con1
--send
SELECT b FROM t1 WHERE a=3 FOR UPDATE;
connection con2;
# Check that the above SELECT is blocked
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = 'statistics' and
info = 'SELECT b FROM t1 WHERE a=3 FOR UPDATE';
--source include/wait_condition.inc
SET DEBUG_SYNC='now SIGNAL select4';
connection default;
reap;
connection con1;
--error ER_DUP_ENTRY
reap;
SET DEBUG_SYNC='write_row_noreplace SIGNAL insert5 WAIT_FOR select5';
--send
LOAD DATA INFILE '../../std_data/loaddata5.dat' IGNORE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b);
connection default;
SET DEBUG_SYNC='now WAIT_FOR insert5';
SELECT * FROM t1;
# this should S-lock; no conflict
SELECT * FROM t1 WHERE a=3 LOCK IN SHARE MODE;
# this should X-lock, conflicting with the S-lock of the IGNORE in con1
--send
SELECT * FROM t1 WHERE a=3 FOR UPDATE;
connection con2;
# Check that the above SELECT is blocked
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = 'statistics' and
info = 'SELECT * FROM t1 WHERE a=3 FOR UPDATE';
--source include/wait_condition.inc
SET DEBUG_SYNC='now SIGNAL select5';
connection con1;
reap;
connection default;
reap;
connection con1;
SET DEBUG_SYNC='write_row_replace SIGNAL insert6 WAIT_FOR select6';
--send
LOAD DATA INFILE '../../std_data/loaddata5.dat' REPLACE INTO TABLE t1 FIELDS TERMINATED BY '' ENCLOSED BY '' (a, b);
connection default;
SET DEBUG_SYNC='now WAIT_FOR insert6';
SELECT * FROM t1;
# this should conflict with the X-lock acquired by the REPLACE
--send
SELECT a,b FROM t1 LOCK IN SHARE MODE;
connection con2;
# Check that the above SELECT is blocked
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = 'Sending data' and
info = 'SELECT a,b FROM t1 LOCK IN SHARE MODE';
--source include/wait_condition.inc
SET DEBUG_SYNC='now SIGNAL select6';
connection con1;
reap;
connection default;
reap;
disconnect con1;
disconnect con2;
connection default;
SET DEBUG_SYNC='RESET';
DROP TABLE t1;

View File

@ -1693,3 +1693,17 @@ INSERT INTO t1 SELECT t1.* FROM t1,t1 t2,t1 t3,t1 t4,t1 t5,t1 t6;
SELECT * FROM t1 ORDER BY f LIMIT 1;
DROP TABLE t1;
SET sort_buffer_size=DEFAULT;
--echo #
--echo # BUG#11758979 - 51252: ARCHIVE TABLES CAUSE 100% CPU USAGE
--echo # AND HANG IN SHOW TABLE STATUS
--echo # (to be executed with valgrind)
CREATE TABLE t1(a BLOB, b VARCHAR(200)) ENGINE=ARCHIVE;
INSERT INTO t1 VALUES(NULL, '');
FLUSH TABLE t1;
--echo # we need this select to workaround BUG#11764364
SELECT * FROM t1;
CHECKSUM TABLE t1 EXTENDED;
FLUSH TABLE t1;
OPTIMIZE TABLE t1;
DROP TABLE t1;

View File

@ -12,4 +12,4 @@
kill : Bug#11748945 2008-12-03 HHunger need some changes to be robust enough for pushbuild.
read_many_rows_innodb : Bug#11748886 2010-11-15 mattiasj report already exists
main.log_tables-big : Bug#11756699 2010-11-15 mattiasj report already exists
query_cache_28249 : Bug#12584161 2011-11-17 joh fails sporadically in 5.1 only

View File

@ -1,5 +1,4 @@
/*
Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -12,8 +11,8 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/
#define DONT_DEFINE_VOID 1
@ -57,10 +56,11 @@ void my_init_stacktrace()
static void print_buffer(char *buffer, size_t count)
{
const char s[]= " ";
for (; count && *buffer; --count)
{
int c= (int) *buffer++;
fputc(isprint(c) ? c : ' ', stderr);
my_write_stderr(isprint(*buffer) ? buffer : s, 1);
++buffer;
}
}
@ -124,10 +124,10 @@ static int safe_print_str(const char *addr, int max_len)
/* Output a new line if something was printed. */
if (total != (size_t) max_len)
fputc('\n', stderr);
my_safe_printf_stderr("%s", "\n");
if (nbytes == -1)
fprintf(stderr, "Can't read from address %p: %m.\n", addr);
my_safe_printf_stderr("Can't read from address %p\n", addr);
close(fd);
@ -149,13 +149,13 @@ void my_safe_print_str(const char* val, int max_len)
if (!PTR_SANE(val))
{
fprintf(stderr, "is an invalid pointer\n");
my_safe_printf_stderr("%s", "is an invalid pointer\n");
return;
}
for (; max_len && PTR_SANE(val) && *val; --max_len)
fputc(*val++, stderr);
fputc('\n', stderr);
my_write_stderr((val++), 1);
my_safe_printf_stderr("%s", "\n");
}
#if defined(HAVE_PRINTSTACK)
@ -167,14 +167,15 @@ void my_print_stacktrace(uchar* stack_bottom __attribute__((unused)),
ulong thread_stack __attribute__((unused)))
{
if (printstack(fileno(stderr)) == -1)
fprintf(stderr, "Error when traversing the stack, stack appears corrupt.\n");
my_safe_printf_stderr("%s",
"Error when traversing the stack, stack appears corrupt.\n");
else
fprintf(stderr,
"Please read "
"http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
"and follow instructions on how to resolve the stack trace.\n"
"Resolved stack trace is much more helpful in diagnosing the\n"
"problem, so please do resolve it\n");
my_safe_printf_stderr("%s"
"Please read "
"http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
"and follow instructions on how to resolve the stack trace.\n"
"Resolved stack trace is much more helpful in diagnosing the\n"
"problem, so please do resolve it\n");
}
#elif HAVE_BACKTRACE && (HAVE_BACKTRACE_SYMBOLS || HAVE_BACKTRACE_SYMBOLS_FD)
@ -212,9 +213,9 @@ static void my_demangle_symbols(char **addrs, int n)
}
if (demangled)
fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end);
my_safe_printf_stderr("%s(%s+%s\n", addrs[i], demangled, end);
else
fprintf(stderr, "%s\n", addrs[i]);
my_safe_printf_stderr("%s\n", addrs[i]);
}
}
@ -225,8 +226,8 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
void *addrs[128];
char **strings= NULL;
int n = backtrace(addrs, array_elements(addrs));
fprintf(stderr, "stack_bottom = %p thread_stack 0x%lx\n",
stack_bottom, thread_stack);
my_safe_printf_stderr("stack_bottom = %p thread_stack 0x%lx\n",
stack_bottom, thread_stack);
#if BACKTRACE_DEMANGLE
if ((strings= backtrace_symbols(addrs, n)))
{
@ -319,8 +320,9 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
#endif
if (!fp)
{
fprintf(stderr, "frame pointer is NULL, did you compile with\n\
-fomit-frame-pointer? Aborting backtrace!\n");
my_safe_printf_stderr("%s",
"frame pointer is NULL, did you compile with\n"
"-fomit-frame-pointer? Aborting backtrace!\n");
return;
}
@ -328,24 +330,28 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
{
ulong tmp= min(0x10000,thread_stack);
/* Assume that the stack starts at the previous even 65K */
stack_bottom= (uchar*) (((ulong) &fp + tmp) &
~(ulong) 0xFFFF);
fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", fp);
stack_bottom= (uchar*) (((ulong) &fp + tmp) & ~(ulong) 0xFFFF);
my_safe_printf_stderr("Cannot determine thread, fp=%p, "
"backtrace may not be correct.\n", fp);
}
if (fp > (uchar**) stack_bottom ||
fp < (uchar**) stack_bottom - thread_stack)
{
fprintf(stderr, "Bogus stack limit or frame pointer,\
fp=%p, stack_bottom=%p, thread_stack=%ld, aborting backtrace.\n",
fp, stack_bottom, thread_stack);
my_safe_printf_stderr("Bogus stack limit or frame pointer, "
"fp=%p, stack_bottom=%p, thread_stack=%ld, "
"aborting backtrace.\n",
fp, stack_bottom, thread_stack);
return;
}
fprintf(stderr, "Stack range sanity check OK, backtrace follows:\n");
my_safe_printf_stderr("%s",
"Stack range sanity check OK, backtrace follows:\n");
#if defined(__alpha__) && defined(__GNUC__)
fprintf(stderr, "Warning: Alpha stacks are difficult -\
will be taking some wild guesses, stack trace may be incorrect or \
terminate abruptly\n");
my_safe_printf_stderr("%s",
"Warning: Alpha stacks are difficult -"
"will be taking some wild guesses, stack trace may be incorrect or "
"terminate abruptly\n");
/* On Alpha, we need to get pc */
__asm __volatile__ ("bsr %0, do_next; do_next: "
:"=r"(pc)
@ -359,8 +365,9 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
{
#if defined(__i386__) || defined(__x86_64__)
uchar** new_fp = (uchar**)*fp;
fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ?
*(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1));
my_safe_printf_stderr("%p\n",
frame_count == sigreturn_frame_count ?
*(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1));
#endif /* defined(__386__) || defined(__x86_64__) */
#if defined(__alpha__) && defined(__GNUC__)
@ -374,38 +381,40 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
{
pc = find_prev_pc(pc, fp);
if (pc)
fprintf(stderr, "%p\n", pc);
my_safe_printf_stderr("%p\n", pc);
else
{
fprintf(stderr, "Not smart enough to deal with the rest\
of this stack\n");
my_safe_printf_stderr("%s",
"Not smart enough to deal with the rest of this stack\n");
goto end;
}
}
else
{
fprintf(stderr, "Not smart enough to deal with the rest of this stack\n");
my_safe_printf_stderr("%s",
"Not smart enough to deal with the rest of this stack\n");
goto end;
}
#endif /* defined(__alpha__) && defined(__GNUC__) */
if (new_fp <= fp )
{
fprintf(stderr, "New value of fp=%p failed sanity check,\
terminating stack trace!\n", new_fp);
my_safe_printf_stderr("New value of fp=%p failed sanity check, "
"terminating stack trace!\n", new_fp);
goto end;
}
fp = new_fp;
++frame_count;
}
fprintf(stderr, "Stack trace seems successful - bottom reached\n");
my_safe_printf_stderr("%s",
"Stack trace seems successful - bottom reached\n");
end:
fprintf(stderr,
"Please read http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
"and follow instructions on how to resolve the stack trace.\n"
"Resolved stack trace is much more helpful in diagnosing the\n"
"problem, so please do resolve it\n");
my_safe_printf_stderr("%s",
"Please read "
"http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
"and follow instructions on how to resolve the stack trace.\n"
"Resolved stack trace is much more helpful in diagnosing the\n"
"problem, so please do resolve it\n");
}
#endif /* TARGET_OS_LINUX */
#endif /* HAVE_STACKTRACE */
@ -670,7 +679,7 @@ void my_print_stacktrace(uchar* unused1, ulong unused2)
&(package.sym));
have_source= pSymGetLineFromAddr64(hProcess, addr, &line_offset, &line);
fprintf(stderr, "%p ", addr);
my_safe_printf_stderr("%p ", addr);
if(have_module)
{
char *base_image_name= strrchr(module.ImageName, '\\');
@ -678,12 +687,13 @@ void my_print_stacktrace(uchar* unused1, ulong unused2)
base_image_name++;
else
base_image_name= module.ImageName;
fprintf(stderr, "%s!", base_image_name);
my_safe_printf_stderr("%s!", base_image_name);
}
if(have_symbol)
fprintf(stderr, "%s()", package.sym.Name);
my_safe_printf_stderr("%s()", package.sym.Name);
else if(have_module)
fprintf(stderr, "???");
my_safe_printf_stderr("%s", "???");
if(have_source)
{
@ -692,11 +702,11 @@ void my_print_stacktrace(uchar* unused1, ulong unused2)
base_file_name++;
else
base_file_name= line.FileName;
fprintf(stderr,"[%s:%u]", base_file_name, line.LineNumber);
my_safe_printf_stderr("[%s:%u]",
base_file_name, line.LineNumber);
}
fprintf(stderr, "\n");
my_safe_printf_stderr("%s", "\n");
}
fflush(stderr);
}
@ -733,22 +743,22 @@ void my_write_core(int unused)
if(pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
hFile, MiniDumpNormal, &info, 0, 0))
{
fprintf(stderr, "Minidump written to %s\n",
_fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname);
my_safe_printf_stderr("Minidump written to %s\n",
_fullpath(path, dump_fname, sizeof(path)) ?
path : dump_fname);
}
else
{
fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n",
GetLastError());
my_safe_printf_stderr("MiniDumpWriteDump() failed, last error %u\n",
(uint) GetLastError());
}
CloseHandle(hFile);
}
else
{
fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname,
GetLastError());
my_safe_printf_stderr("CreateFile(%s) failed, last error %u\n",
dump_fname, (uint) GetLastError());
}
fflush(stderr);
}
@ -756,11 +766,212 @@ void my_safe_print_str(const char *val, int len)
{
__try
{
fprintf(stderr,"=%.*s\n", len, val);
my_write_stderr(val, len);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
fprintf(stderr,"is an invalid string pointer\n");
my_safe_printf_stderr("%s", "is an invalid string pointer\n");
}
}
#endif /*__WIN__*/
#ifdef __WIN__
size_t my_write_stderr(const void *buf, size_t count)
{
DWORD bytes_written;
SetFilePointer(GetStdHandle(STD_ERROR_HANDLE), 0, NULL, FILE_END);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), buf, count, &bytes_written, NULL);
return bytes_written;
}
#else
size_t my_write_stderr(const void *buf, size_t count)
{
return (size_t) write(STDERR_FILENO, buf, count);
}
#endif
static const char digits[]= "0123456789abcdef";
char *my_safe_utoa(int base, ulonglong val, char *buf)
{
*buf--= 0;
do {
*buf--= digits[val % base];
} while ((val /= base) != 0);
return buf + 1;
}
char *my_safe_itoa(int base, longlong val, char *buf)
{
char *orig_buf= buf;
const my_bool is_neg= (val < 0);
*buf--= 0;
if (is_neg)
val= -val;
if (is_neg && base == 16)
{
int ix;
val-= 1;
for (ix= 0; ix < 16; ++ix)
buf[-ix]= '0';
}
do {
*buf--= digits[val % base];
} while ((val /= base) != 0);
if (is_neg && base == 10)
*buf--= '-';
if (is_neg && base == 16)
{
int ix;
buf= orig_buf - 1;
for (ix= 0; ix < 16; ++ix, --buf)
{
switch (*buf)
{
case '0': *buf= 'f'; break;
case '1': *buf= 'e'; break;
case '2': *buf= 'd'; break;
case '3': *buf= 'c'; break;
case '4': *buf= 'b'; break;
case '5': *buf= 'a'; break;
case '6': *buf= '9'; break;
case '7': *buf= '8'; break;
case '8': *buf= '7'; break;
case '9': *buf= '6'; break;
case 'a': *buf= '5'; break;
case 'b': *buf= '4'; break;
case 'c': *buf= '3'; break;
case 'd': *buf= '2'; break;
case 'e': *buf= '1'; break;
case 'f': *buf= '0'; break;
}
}
}
return buf+1;
}
static const char *check_longlong(const char *fmt, my_bool *have_longlong)
{
*have_longlong= FALSE;
if (*fmt == 'l')
{
fmt++;
if (*fmt != 'l')
*have_longlong= (sizeof(long) == sizeof(longlong));
else
{
fmt++;
*have_longlong= TRUE;
}
}
return fmt;
}
static size_t my_safe_vsnprintf(char *to, size_t size,
const char* format, va_list ap)
{
char *start= to;
char *end= start + size - 1;
for (; *format; ++format)
{
my_bool have_longlong = FALSE;
if (*format != '%')
{
if (to == end) /* end of buffer */
break;
*to++= *format; /* copy ordinary char */
continue;
}
++format; /* skip '%' */
format= check_longlong(format, &have_longlong);
switch (*format)
{
case 'd':
case 'i':
case 'u':
case 'x':
case 'p':
{
longlong ival= 0;
ulonglong uval = 0;
if (*format == 'p')
have_longlong= (sizeof(void *) == sizeof(longlong));
if (have_longlong)
{
if (*format == 'u')
uval= va_arg(ap, ulonglong);
else
ival= va_arg(ap, longlong);
}
else
{
if (*format == 'u')
uval= va_arg(ap, unsigned int);
else
ival= va_arg(ap, int);
}
{
char buff[22];
const int base= (*format == 'x' || *format == 'p') ? 16 : 10;
char *val_as_str= (*format == 'u') ?
my_safe_utoa(base, uval, &buff[sizeof(buff)-1]) :
my_safe_itoa(base, ival, &buff[sizeof(buff)-1]);
/* Strip off "ffffffff" if we have 'x' format without 'll' */
if (*format == 'x' && !have_longlong && ival < 0)
val_as_str+= 8;
while (*val_as_str && to < end)
*to++= *val_as_str++;
continue;
}
}
case 's':
{
const char *val= va_arg(ap, char*);
if (!val)
val= "(null)";
while (*val && to < end)
*to++= *val++;
continue;
}
}
}
*to= 0;
return to - start;
}
size_t my_safe_snprintf(char* to, size_t n, const char* fmt, ...)
{
size_t result;
va_list args;
va_start(args,fmt);
result= my_safe_vsnprintf(to, n, fmt, args);
va_end(args);
return result;
}
size_t my_safe_printf_stderr(const char* fmt, ...)
{
char to[512];
size_t result;
va_list args;
va_start(args,fmt);
result= my_safe_vsnprintf(to, sizeof(to), fmt, args);
va_end(args);
my_write_stderr(to, result);
return result;
}

View File

@ -65,6 +65,7 @@ SET (SQL_SOURCE
sql_list.cc sql_load.cc sql_manager.cc sql_map.cc sql_parse.cc
sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc
debug_sync.cc debug_sync.h
signal_handler.cc
sql_repl.cc sql_select.cc sql_show.cc sql_state.c sql_string.cc
sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc
sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc
@ -113,7 +114,7 @@ IF(MSVC AND NOT WITHOUT_DYNAMIC_PLUGINS)
ADD_CUSTOM_COMMAND(TARGET mysqld PRE_LINK
COMMAND cscript ARGS //nologo ${PROJECT_SOURCE_DIR}/win/create_def_file.js
${PLATFORM} ${LIB_LOCATIONS} > mysqld.def
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/sql)
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
ENDIF(MSVC AND NOT WITHOUT_DYNAMIC_PLUGINS)
ADD_DEPENDENCIES(sql GenError)

View File

@ -103,6 +103,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
records.cc filesort.cc handler.cc \
ha_partition.cc \
debug_sync.cc \
signal_handler.cc \
sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \

View File

@ -2128,6 +2128,23 @@ public:
uchar *from_null_ptr,*to_null_ptr;
my_bool *null_row;
uint from_bit,to_bit;
/**
Number of bytes in the fields pointed to by 'from_ptr' and
'to_ptr'. Usually this is the number of bytes that are copied from
'from_ptr' to 'to_ptr'.
For variable-length fields (VARCHAR), the first byte(s) describe
the actual length of the text. For VARCHARs with length
< 256 there is 1 length byte
>= 256 there is 2 length bytes
Thus, if from_field is VARCHAR(10), from_length (and in most cases
to_length) is 11. For VARCHAR(1024), the length is 1026. @see
Field_varstring::length_bytes
Note that for VARCHARs, do_copy() will be do_varstring*() which
only copies the length-bytes (1 or 2) + the actual length of the
text instead of from/to_length bytes. @see get_copy_func()
*/
uint from_length,to_length;
Field *from_field,*to_field;
String tmp; // For items

View File

@ -707,7 +707,7 @@ Copy_field::get_copy_func(Field *to,Field *from)
if (((Field_varstring*) to)->length_bytes !=
((Field_varstring*) from)->length_bytes)
return do_field_string;
if (to_length != from_length)
else
return (((Field_varstring*) to)->length_bytes == 1 ?
(from->charset()->mbmaxlen == 1 ? do_varstring1 :
do_varstring1_mb) :

View File

@ -1854,7 +1854,7 @@ static void setup_windows_event_source()
static int find_uniq_filename(char *name)
{
long number;
long number= 0;
uint i;
char buff[FN_REFLEN];
struct st_my_dir *dir_info;

View File

@ -124,9 +124,6 @@ extern "C" { // Because of SCO 3.2V4.2
#ifdef __WIN__
#include <crtdbg.h>
#define SIGNAL_FMT "exception 0x%x"
#else
#define SIGNAL_FMT "signal %d"
#endif
#ifdef __NETWARE__
@ -269,7 +266,7 @@ inline void setup_fpu()
extern "C" int gethostname(char *name, int namelen);
#endif
extern "C" sig_handler handle_segfault(int sig);
extern "C" sig_handler handle_fatal_signal(int sig);
#if defined(__linux__)
#define ENABLE_TEMP_POOL 1
@ -415,6 +412,10 @@ TYPELIB log_output_typelib= {array_elements(log_output_names)-1,"",
/* static variables */
#ifdef HAVE_NPTL
volatile sig_atomic_t ld_assume_kernel_is_set= 0;
#endif
/* the default log output is log tables */
static bool lower_case_table_names_used= 0;
static bool max_long_data_size_used= false;
@ -424,7 +425,7 @@ static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0;
static my_bool opt_short_log_format= 0;
static uint kill_cached_threads, wake_thread;
static ulong killed_threads, thread_created;
static ulong max_used_connections;
ulong max_used_connections;
static ulong my_bind_addr; /**< the address we bind to */
static volatile ulong cached_thread_count= 0;
static const char *sql_mode_str= "OFF";
@ -553,7 +554,7 @@ TYPELIB binlog_format_typelib=
ulong opt_binlog_format_id= (ulong) BINLOG_FORMAT_UNSPEC;
const char *opt_binlog_format= binlog_format_names[opt_binlog_format_id];
#ifdef HAVE_INITGROUPS
static bool calling_initgroups= FALSE; /**< Used in SIGSEGV handler. */
volatile sig_atomic_t calling_initgroups= 0; /**< Used in SIGSEGV handler. */
#endif
uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options;
uint mysqld_port_timeout;
@ -727,7 +728,7 @@ char *opt_logname, *opt_slow_logname;
/* Static variables */
static bool kill_in_progress, segfaulted;
static volatile sig_atomic_t kill_in_progress;
#ifdef HAVE_STACK_TRACE_ON_SEGV
static my_bool opt_do_pstack;
#endif /* HAVE_STACK_TRACE_ON_SEGV */
@ -1616,9 +1617,9 @@ static void set_user(const char *user, struct passwd *user_info_arg)
calling_initgroups as a flag to the SIGSEGV handler that is then used to
output a specific message to help the user resolve this problem.
*/
calling_initgroups= TRUE;
calling_initgroups= 1;
initgroups((char*) user, user_info_arg->pw_gid);
calling_initgroups= FALSE;
calling_initgroups= 0;
#endif
if (setgid(user_info_arg->pw_gid) == -1)
{
@ -2170,7 +2171,7 @@ LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers)
__try
{
my_set_exception_pointers(ex_pointers);
handle_segfault(ex_pointers->ExceptionRecord->ExceptionCode);
handle_fatal_signal(ex_pointers->ExceptionRecord->ExceptionCode);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
@ -2481,161 +2482,6 @@ extern "C" char *my_demangle(const char *mangled_name, int *status)
#endif
extern "C" sig_handler handle_segfault(int sig)
{
time_t curr_time;
struct tm tm;
/*
Strictly speaking, one needs a mutex here
but since we have got SIGSEGV already, things are a mess
so not having the mutex is not as bad as possibly using a buggy
mutex - so we keep things simple
*/
if (segfaulted)
{
fprintf(stderr, "Fatal " SIGNAL_FMT " while backtracing\n", sig);
exit(1);
}
segfaulted = 1;
curr_time= my_time(0);
localtime_r(&curr_time, &tm);
fprintf(stderr,"\
%02d%02d%02d %2d:%02d:%02d - mysqld got " SIGNAL_FMT " ;\n\
This could be because you hit a bug. It is also possible that this binary\n\
or one of the libraries it was linked against is corrupt, improperly built,\n\
or misconfigured. This error can also be caused by malfunctioning hardware.\n",
tm.tm_year % 100, tm.tm_mon+1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec,
sig);
fprintf(stderr, "\
We will try our best to scrape up some info that will hopefully help diagnose\n\
the problem, but since we have already crashed, something is definitely wrong\n\
and this may fail.\n\n");
fprintf(stderr, "key_buffer_size=%lu\n",
(ulong) dflt_key_cache->key_cache_mem_size);
fprintf(stderr, "read_buffer_size=%ld\n", (long) global_system_variables.read_buff_size);
fprintf(stderr, "max_used_connections=%lu\n", max_used_connections);
fprintf(stderr, "max_threads=%u\n", thread_scheduler.max_threads);
fprintf(stderr, "threads_connected=%u\n", thread_count);
fprintf(stderr, "It is possible that mysqld could use up to \n\
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = %lu K\n\
bytes of memory\n", ((ulong) dflt_key_cache->key_cache_mem_size +
(global_system_variables.read_buff_size +
global_system_variables.sortbuff_size) *
thread_scheduler.max_threads +
max_connections * sizeof(THD)) / 1024);
fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n");
#if defined(HAVE_LINUXTHREADS)
if (sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS)
{
fprintf(stderr, "\
You seem to be running 32-bit Linux and have %d concurrent connections.\n\
If you have not changed STACK_SIZE in LinuxThreads and built the binary \n\
yourself, LinuxThreads is quite likely to steal a part of the global heap for\n\
the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n",
thread_count);
}
#endif /* HAVE_LINUXTHREADS */
#ifdef HAVE_STACKTRACE
THD *thd=current_thd;
if (!(test_flags & TEST_NO_STACKTRACE))
{
fprintf(stderr, "Thread pointer: 0x%lx\n", (long) thd);
fprintf(stderr, "Attempting backtrace. You can use the following "
"information to find out\nwhere mysqld died. If "
"you see no messages after this, something went\n"
"terribly wrong...\n");
my_print_stacktrace(thd ? (uchar*) thd->thread_stack : NULL,
my_thread_stack_size);
}
if (thd)
{
const char *kreason= "UNKNOWN";
switch (thd->killed) {
case THD::NOT_KILLED:
kreason= "NOT_KILLED";
break;
case THD::KILL_BAD_DATA:
kreason= "KILL_BAD_DATA";
break;
case THD::KILL_CONNECTION:
kreason= "KILL_CONNECTION";
break;
case THD::KILL_QUERY:
kreason= "KILL_QUERY";
break;
case THD::KILLED_NO_VALUE:
kreason= "KILLED_NO_VALUE";
break;
}
fprintf(stderr, "\nTrying to get some variables.\n"
"Some pointers may be invalid and cause the dump to abort.\n");
fprintf(stderr, "Query (%p): ", thd->query());
my_safe_print_str(thd->query(), min(1024, thd->query_length()));
fprintf(stderr, "Connection ID (thread ID): %lu\n", (ulong) thd->thread_id);
fprintf(stderr, "Status: %s\n", kreason);
fputc('\n', stderr);
}
fprintf(stderr, "\
The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains\n\
information that should help you find out what is causing the crash.\n");
fflush(stderr);
#endif /* HAVE_STACKTRACE */
#ifdef HAVE_INITGROUPS
if (calling_initgroups)
fprintf(stderr, "\n\
This crash occured while the server was calling initgroups(). This is\n\
often due to the use of a mysqld that is statically linked against glibc\n\
and configured to use LDAP in /etc/nsswitch.conf. You will need to either\n\
upgrade to a version of glibc that does not have this problem (2.3.4 or\n\
later when used with nscd), disable LDAP in your nsswitch.conf, or use a\n\
mysqld that is not statically linked.\n");
#endif
#ifdef HAVE_NPTL
if (thd_lib_detected == THD_LIB_LT && !getenv("LD_ASSUME_KERNEL"))
fprintf(stderr,"\n\
You are running a statically-linked LinuxThreads binary on an NPTL system.\n\
This can result in crashes on some distributions due to LT/NPTL conflicts.\n\
You should either build a dynamically-linked binary, or force LinuxThreads\n\
to be used with the LD_ASSUME_KERNEL environment variable. Please consult\n\
the documentation for your distribution on how to do that.\n");
#endif
if (locked_in_memory)
{
fprintf(stderr, "\n\
The \"--memlock\" argument, which was enabled, uses system calls that are\n\
unreliable and unstable on some operating systems and operating-system\n\
versions (notably, some versions of Linux). This crash could be due to use\n\
of those buggy OS calls. You should consider whether you really need the\n\
\"--memlock\" parameter and/or consult the OS distributer about \"mlockall\"\n\
bugs.\n");
}
#ifdef HAVE_WRITE_CORE
if (test_flags & TEST_CORE_ON_SIGNAL)
{
fprintf(stderr, "Writing a core file\n");
fflush(stderr);
my_write_core(sig);
}
#endif
#ifndef __WIN__
/* On Windows, do not terminate, but pass control to exception filter */
exit(1);
#endif
}
#if !defined(__WIN__) && !defined(__NETWARE__)
#ifndef SA_RESETHAND
#define SA_RESETHAND 0
@ -2664,9 +2510,9 @@ static void init_signals(void)
my_init_stacktrace();
#endif
#if defined(__amiga__)
sa.sa_handler=(void(*)())handle_segfault;
sa.sa_handler=(void(*)())handle_fatal_signal;
#else
sa.sa_handler=handle_segfault;
sa.sa_handler=handle_fatal_signal;
#endif
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGABRT, &sa, NULL);
@ -4363,6 +4209,10 @@ int win_main(int argc, char **argv)
int main(int argc, char **argv)
#endif
{
#ifdef HAVE_NPTL
ld_assume_kernel_is_set= (getenv("LD_ASSUME_KERNEL") != 0);
#endif
MY_INIT(argv[0]); // init my_sys library & pthreads
/* nothing should come before this line ^^^ */
@ -7876,7 +7726,7 @@ static int mysql_init_variables(void)
opt_secure_file_priv= 0;
opt_bootstrap= opt_myisam_log= 0;
mqh_used= 0;
segfaulted= kill_in_progress= 0;
kill_in_progress= 0;
cleanup_done= 0;
defaults_argc= 0;
defaults_argv= 0;

257
sql/signal_handler.cc Normal file
View File

@ -0,0 +1,257 @@
/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA */
#include "my_global.h"
#include <signal.h>
#include "mysql_priv.h"
#include "my_stacktrace.h"
#ifdef __WIN__
#include <crtdbg.h>
#define SIGNAL_FMT "exception 0x%x"
#else
#define SIGNAL_FMT "signal %d"
#endif
/*
We are handling signals in this file.
Any global variables we read should be 'volatile sig_atomic_t'
to guarantee that we read some consistent value.
*/
static volatile sig_atomic_t segfaulted= 0;
extern ulong max_used_connections;
extern volatile sig_atomic_t calling_initgroups;
#ifdef HAVE_NPTL
extern volatile sig_atomic_t ld_assume_kernel_is_set;
#endif
/**
* Handler for fatal signals
*
* Fatal events (seg.fault, bus error etc.) will trigger
* this signal handler. The handler will try to dump relevant
* debugging information to stderr and dump a core image.
*
* Signal handlers can only use a set of 'safe' system calls
* and library functions. A list of safe calls in POSIX systems
* are available at:
* http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
* For MS Windows, guidelines are available at:
* http://msdn.microsoft.com/en-us/library/xdkz3x12(v=vs.71).aspx
*
* @param sig Signal number
*/
extern "C" sig_handler handle_fatal_signal(int sig)
{
if (segfaulted)
{
my_safe_printf_stderr("Fatal " SIGNAL_FMT " while backtracing\n", sig);
_exit(1); /* Quit without running destructors */
}
segfaulted = 1;
#ifdef __WIN__
SYSTEMTIME utc_time;
GetSystemTime(&utc_time);
const long hrs= utc_time.wHour;
const long mins= utc_time.wMinute;
const long secs= utc_time.wSecond;
#else
/* Using time() instead of my_time() to avoid looping */
const time_t curr_time= time(NULL);
/* Calculate time of day */
const long tmins = curr_time / 60;
const long thrs = tmins / 60;
const long hrs = thrs % 24;
const long mins = tmins % 60;
const long secs = curr_time % 60;
#endif
char hrs_buf[3]= "00";
char mins_buf[3]= "00";
char secs_buf[3]= "00";
my_safe_itoa(10, hrs, &hrs_buf[2]);
my_safe_itoa(10, mins, &mins_buf[2]);
my_safe_itoa(10, secs, &secs_buf[2]);
my_safe_printf_stderr("%s:%s:%s UTC - mysqld got " SIGNAL_FMT " ;\n",
hrs_buf, mins_buf, secs_buf, sig);
my_safe_printf_stderr("%s",
"This could be because you hit a bug. It is also possible that this binary\n"
"or one of the libraries it was linked against is corrupt, improperly built,\n"
"or misconfigured. This error can also be caused by malfunctioning hardware.\n");
my_safe_printf_stderr("%s",
"We will try our best to scrape up some info that will hopefully help\n"
"diagnose the problem, but since we have already crashed, \n"
"something is definitely wrong and this may fail.\n\n");
my_safe_printf_stderr("key_buffer_size=%lu\n",
(ulong) dflt_key_cache->key_cache_mem_size);
my_safe_printf_stderr("read_buffer_size=%ld\n",
(long) global_system_variables.read_buff_size);
my_safe_printf_stderr("max_used_connections=%lu\n",
(ulong) max_used_connections);
my_safe_printf_stderr("max_threads=%u\n",
(uint) thread_scheduler.max_threads);
my_safe_printf_stderr("thread_count=%u\n", (uint) thread_count);
my_safe_printf_stderr("connection_count=%u\n", (uint) connection_count);
my_safe_printf_stderr("It is possible that mysqld could use up to \n"
"key_buffer_size + "
"(read_buffer_size + sort_buffer_size)*max_threads = "
"%lu K bytes of memory\n",
((ulong) dflt_key_cache->key_cache_mem_size +
(global_system_variables.read_buff_size +
global_system_variables.sortbuff_size) *
thread_scheduler.max_threads +
max_connections * sizeof(THD)) / 1024);
my_safe_printf_stderr("%s",
"Hope that's ok; if not, decrease some variables in the equation.\n\n");
#if defined(HAVE_LINUXTHREADS)
if (sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS)
{
my_safe_printf_stderr(
"You seem to be running 32-bit Linux and have "
"%d concurrent connections.\n"
"If you have not changed STACK_SIZE in LinuxThreads "
"and built the binary \n"
"yourself, LinuxThreads is quite likely to steal "
"a part of the global heap for\n"
"the thread stack. Please read "
"http://dev.mysql.com/doc/mysql/en/linux-installation.html\n\n"
thread_count);
}
#endif /* HAVE_LINUXTHREADS */
#ifdef HAVE_STACKTRACE
THD *thd=current_thd;
if (!(test_flags & TEST_NO_STACKTRACE))
{
my_safe_printf_stderr("Thread pointer: 0x%p\n", thd);
my_safe_printf_stderr("%s",
"Attempting backtrace. You can use the following "
"information to find out\n"
"where mysqld died. If you see no messages after this, something went\n"
"terribly wrong...\n");
my_print_stacktrace(thd ? (uchar*) thd->thread_stack : NULL,
my_thread_stack_size);
}
if (thd)
{
const char *kreason= "UNKNOWN";
switch (thd->killed) {
case THD::NOT_KILLED:
kreason= "NOT_KILLED";
break;
case THD::KILL_BAD_DATA:
kreason= "KILL_BAD_DATA";
break;
case THD::KILL_CONNECTION:
kreason= "KILL_CONNECTION";
break;
case THD::KILL_QUERY:
kreason= "KILL_QUERY";
break;
case THD::KILLED_NO_VALUE:
kreason= "KILLED_NO_VALUE";
break;
}
my_safe_printf_stderr("%s", "\n"
"Trying to get some variables.\n"
"Some pointers may be invalid and cause the dump to abort.\n");
my_safe_printf_stderr("Query (%p): ", thd->query());
my_safe_print_str(thd->query(), min(1024U, thd->query_length()));
my_safe_printf_stderr("Connection ID (thread ID): %lu\n",
(ulong) thd->thread_id);
my_safe_printf_stderr("Status: %s\n\n", kreason);
}
my_safe_printf_stderr("%s",
"The manual page at "
"http://dev.mysql.com/doc/mysql/en/crashing.html contains\n"
"information that should help you find out what is causing the crash.\n");
#endif /* HAVE_STACKTRACE */
#ifdef HAVE_INITGROUPS
if (calling_initgroups)
{
my_safe_printf_stderr("%s", "\n"
"This crash occured while the server was calling initgroups(). This is\n"
"often due to the use of a mysqld that is statically linked against \n"
"glibc and configured to use LDAP in /etc/nsswitch.conf.\n"
"You will need to either upgrade to a version of glibc that does not\n"
"have this problem (2.3.4 or later when used with nscd),\n"
"disable LDAP in your nsswitch.conf, or use a "
"mysqld that is not statically linked.\n");
}
#endif
#ifdef HAVE_NPTL
if (thd_lib_detected == THD_LIB_LT && !ld_assume_kernel_is_set)
{
my_safe_printf_stderr("%s",
"You are running a statically-linked LinuxThreads binary on an NPTL\n"
"system. This can result in crashes on some distributions due to "
"LT/NPTL conflicts.\n"
"You should either build a dynamically-linked binary, "
"or force LinuxThreads\n"
"to be used with the LD_ASSUME_KERNEL environment variable.\n"
"Please consult the documentation for your distribution "
"on how to do that.\n");
}
#endif
if (locked_in_memory)
{
my_safe_printf_stderr("%s", "\n"
"The \"--memlock\" argument, which was enabled, "
"uses system calls that are\n"
"unreliable and unstable on some operating systems and "
"operating-system versions (notably, some versions of Linux).\n"
"This crash could be due to use of those buggy OS calls.\n"
"You should consider whether you really need the "
"\"--memlock\" parameter and/or consult the OS distributer about "
"\"mlockall\" bugs.\n");
}
#ifdef HAVE_WRITE_CORE
if (test_flags & TEST_CORE_ON_SIGNAL)
{
my_safe_printf_stderr("%s", "Writing a core file\n");
my_write_core(sig);
}
#endif
#ifndef __WIN__
/*
Quit, without running destructors (etc.)
On Windows, do not terminate, but pass control to exception filter.
*/
_exit(1); // Using _exit(), since exit() is not async signal safe
#endif
}

View File

@ -63,6 +63,8 @@
#include "slave.h"
#include "rpl_mi.h"
#include "debug_sync.h"
#ifndef EMBEDDED_LIBRARY
static bool delayed_get_table(THD *thd, TABLE_LIST *table_list);
static int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic,
@ -1411,6 +1413,8 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
error= HA_ERR_FOUND_DUPP_KEY; /* Database can't find key */
goto err;
}
DEBUG_SYNC(thd, "write_row_replace");
/* Read all columns for the row we are going to replace */
table->use_all_columns();
/*
@ -1604,6 +1608,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
}
else if ((error=table->file->ha_write_row(table->record[0])))
{
DEBUG_SYNC(thd, "write_row_noreplace");
if (!info->ignore ||
table->file->is_fatal_error(error, HA_CHECK_DUP))
goto err;

View File

@ -10647,6 +10647,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (open_tmp_table(table))
goto err;
// Make empty record so random data is not written to disk
empty_record(table);
thd->mem_root= mem_root_save;
DBUG_RETURN(table);

View File

@ -760,6 +760,7 @@ uint32 ha_archive::max_row_length(const uchar *buf)
ptr != end ;
ptr++)
{
if (!table->field[*ptr]->is_null())
length += 2 + ((Field_blob*)table->field[*ptr])->get_length();
}
@ -1110,6 +1111,17 @@ int ha_archive::unpack_row(azio_stream *file_to_read, uchar *record)
/* Copy null bits */
const uchar *ptr= record_buffer->buffer;
/*
Field::unpack() is not called when field is NULL. For VARCHAR
Field::unpack() only unpacks as much bytes as occupied by field
value. In these cases respective memory area on record buffer is
not initialized.
These uninitialized areas may be accessed by CHECKSUM TABLE or
by optimizer using temporary table (BUG#12997905). We may remove
this memset() when they're fixed.
*/
memset(record, 0, table->s->reclength);
memcpy(record, ptr, table->s->null_bytes);
ptr+= table->s->null_bytes;
for (Field **field=table->field ; *field ; field++)
@ -1578,13 +1590,15 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt)
{
int rc= 0;
const char *old_proc_info;
ha_rows count= share->rows_recorded;
ha_rows count;
DBUG_ENTER("ha_archive::check");
old_proc_info= thd_proc_info(thd, "Checking table");
/* Flush any waiting data */
pthread_mutex_lock(&share->mutex);
azflush(&(share->archive_write), Z_SYNC_FLUSH);
count= share->rows_recorded;
/* Flush any waiting data */
if (share->archive_write_open)
azflush(&(share->archive_write), Z_SYNC_FLUSH);
pthread_mutex_unlock(&share->mutex);
if (init_archive_reader())
@ -1594,18 +1608,34 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt)
start of the file.
*/
read_data_header(&archive);
for (ha_rows cur_count= count; cur_count; cur_count--)
{
if ((rc= get_row(&archive, table->record[0])))
goto error;
}
/*
Now read records that may have been inserted concurrently.
Acquire share->mutex so tail of the table is not modified by
concurrent writers.
*/
pthread_mutex_lock(&share->mutex);
count= share->rows_recorded - count;
if (share->archive_write_open)
azflush(&(share->archive_write), Z_SYNC_FLUSH);
while (!(rc= get_row(&archive, table->record[0])))
count--;
thd_proc_info(thd, old_proc_info);
pthread_mutex_unlock(&share->mutex);
if ((rc && rc != HA_ERR_END_OF_FILE) || count)
{
share->crashed= FALSE;
DBUG_RETURN(HA_ADMIN_CORRUPT);
}
goto error;
thd_proc_info(thd, old_proc_info);
DBUG_RETURN(HA_ADMIN_OK);
error:
thd_proc_info(thd, old_proc_info);
share->crashed= FALSE;
DBUG_RETURN(HA_ADMIN_CORRUPT);
}
/*

View File

@ -4087,8 +4087,7 @@ no_commit:
switch (sql_command) {
case SQLCOM_LOAD:
if ((trx->duplicates
& (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
if (trx->duplicates) {
goto set_max_autoinc;
}
@ -4368,8 +4367,7 @@ ha_innobase::update_row(
&& table->next_number_field
&& new_row == table->record[0]
&& thd_sql_command(user_thd) == SQLCOM_INSERT
&& (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
== TRX_DUP_IGNORE) {
&& trx->duplicates) {
ulonglong auto_inc;
ulonglong col_max_value;
@ -4717,6 +4715,7 @@ ha_innobase::index_read(
index,
(byte*) key_ptr,
(ulint) key_len, prebuilt->trx);
DBUG_ASSERT(prebuilt->search_tuple->n_fields > 0);
} else {
/* We position the cursor to the last or the first entry
in the index */
@ -6172,6 +6171,7 @@ ha_innobase::records_in_range(
void* heap2;
DBUG_ENTER("records_in_range");
DBUG_ASSERT(min_key || max_key);
ut_a(prebuilt->trx == thd_to_trx(ha_thd()));
@ -6202,6 +6202,9 @@ ha_innobase::records_in_range(
(const uchar*) 0),
(ulint) (min_key ? min_key->length : 0),
prebuilt->trx);
DBUG_ASSERT(min_key
? range_start->n_fields > 0
: range_start->n_fields == 0);
row_sel_convert_mysql_key_to_innobase(
range_end, (byte*) key_val_buff2,
@ -6210,6 +6213,9 @@ ha_innobase::records_in_range(
(const uchar*) 0),
(ulint) (max_key ? max_key->length : 0),
prebuilt->trx);
DBUG_ASSERT(max_key
? range_end->n_fields > 0
: range_end->n_fields == 0);
mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
HA_READ_KEY_EXACT);
@ -7095,6 +7101,7 @@ ha_innobase::extra(
break;
case HA_EXTRA_RESET_STATE:
reset_template(prebuilt);
thd_to_trx(ha_thd())->duplicates = 0;
break;
case HA_EXTRA_NO_KEYREAD:
prebuilt->read_just_key = 0;
@ -7112,19 +7119,18 @@ ha_innobase::extra(
parameters below. We must not invoke update_thd()
either, because the calling threads may change.
CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
case HA_EXTRA_IGNORE_DUP_KEY:
case HA_EXTRA_INSERT_WITH_UPDATE:
thd_to_trx(ha_thd())->duplicates |= TRX_DUP_IGNORE;
break;
case HA_EXTRA_NO_IGNORE_DUP_KEY:
thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_IGNORE;
break;
case HA_EXTRA_WRITE_CAN_REPLACE:
thd_to_trx(ha_thd())->duplicates |= TRX_DUP_REPLACE;
break;
case HA_EXTRA_WRITE_CANNOT_REPLACE:
thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_REPLACE;
break;
case HA_EXTRA_NO_IGNORE_DUP_KEY:
thd_to_trx(ha_thd())->duplicates &=
~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
break;
default:/* Do nothing */
;
}

View File

@ -1673,7 +1673,7 @@ row_ins_scan_sec_index_for_duplicate(
btr_pcur_open(index, entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr);
allow_duplicates = thr_get_trx(thr)->duplicates & TRX_DUP_IGNORE;
allow_duplicates = thr_get_trx(thr)->duplicates;
/* Scan index records and check if there is a duplicate */
@ -1813,7 +1813,7 @@ row_ins_duplicate_error_in_clust(
sure that in roll-forward we get the same duplicate
errors as in original execution */
if (trx->duplicates & TRX_DUP_IGNORE) {
if (trx->duplicates) {
/* If the SQL-query will update or replace
duplicate key we will take X-lock for
@ -1855,7 +1855,7 @@ row_ins_duplicate_error_in_clust(
offsets = rec_get_offsets(rec, cursor->index, offsets,
ULINT_UNDEFINED, &heap);
if (trx->duplicates & TRX_DUP_IGNORE) {
if (trx->duplicates) {
/* If the SQL-query will update or replace
duplicate key we will take X-lock for

View File

@ -1,3 +1,15 @@
2011-11-10 The InnoDB Team
* handler/ha_innodb.cc, row/row0ins.c, innodb_replace.test:
Fix Bug#11759688 52020: InnoDB can still deadlock
on just INSERT...ON DUPLICATE KEY a.k.a. the reintroduction of
Bug#7975 deadlock without any locking, simple select and update
2011-11-08 The InnoDB Team
* btr/btr0pcur.c, include/btr0pcur.h, include/btr0pcur.ic:
Fix Bug#13358468 ASSERTION FAILURE IN BTR_PCUR_GET_BLOCK
2011-10-27 The InnoDB Team
* row/row0mysql.c:
@ -55,6 +67,15 @@
* include/trx0undo.h, trx/trx0rec.c, trx/trx0undo.c:
Fix Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE
2011-08-29 The InnoDB Team
* btr/btr0btr.c, btr/btr0cur.c, fsp/fsp0fsp.c,
include/btr0btr.h, include/btr0cur.h, include/fsp0fsp.h,
include/mtr0mtr.h, include/mtr0mtr.ic, mtr/mtr0mtr.c,
row/row0ins.c, row/row0row.c, row/row0upd.c, trx/trx0undo.c:
Fix Bug#12704861 Corruption after a crash during BLOB update
and other regressions from the fix of Bug#12612184
2011-08-15 The InnoDB Team
* btr/btr0btr.c, btr/btr0cur.c, btr/btr0pcur.c, btr/btr0sea.c,
@ -106,6 +127,16 @@
* page/page0zip.c, rem/rem0rec.c:
Fix Bug#61191 question about page_zip_available()
2011-06-16 The InnoDB Team
* btr/btr0btr.c, btr/btr0cur.c, include/btr0btr.h, include/btr0cur.h,
include/btr0cur.ic, include/buf0buf.h, include/buf0buf.ic,
include/page0cur.ic, include/page0page.h, include/page0page.ic,
include/sync0rw.ic, include/sync0sync.h, page/page0cur.c,
page/page0page.c, row/row0ins.c, row/row0upd.c,
sync/sync0rw.c, sync/sync0sync.c:
Fix Bug#12612184 Race condition after btr_cur_pessimistic_update()
2011-06-09 The InnoDB Team
* btr/btr0cur.c, include/rem0rec.h, include/rem0rec.ic,
* row/row0row.c, row/row0vers.c, trx/trx0rec.c:

View File

@ -247,6 +247,8 @@ btr_pcur_restore_position_func(
cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE,
index, latch_mode, btr_pcur_get_btr_cur(cursor), mtr);
cursor->latch_mode = latch_mode;
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
cursor->block_when_stored = btr_pcur_get_block(cursor);
return(FALSE);

View File

@ -946,6 +946,24 @@ buf_pool_free(void)
{
buf_chunk_t* chunk;
buf_chunk_t* chunks;
buf_page_t* bpage;
bpage = UT_LIST_GET_LAST(buf_pool->LRU);
while (bpage != NULL) {
buf_page_t* prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
enum buf_page_state state = buf_page_get_state(bpage);
ut_ad(buf_page_in_file(bpage));
ut_ad(bpage->in_LRU_list);
if (state != BUF_BLOCK_FILE_PAGE) {
/* We must not have any dirty block. */
ut_ad(state == BUF_BLOCK_ZIP_PAGE);
buf_page_free_descriptor(bpage);
}
bpage = prev_bpage;
}
chunks = buf_pool->chunks;
chunk = chunks + buf_pool->n_chunks;

View File

@ -4793,8 +4793,7 @@ no_commit:
switch (sql_command) {
case SQLCOM_LOAD:
if ((trx->duplicates
& (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
if (trx->duplicates) {
goto set_max_autoinc;
}
@ -5070,8 +5069,7 @@ ha_innobase::update_row(
&& table->next_number_field
&& new_row == table->record[0]
&& thd_sql_command(user_thd) == SQLCOM_INSERT
&& (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
== TRX_DUP_IGNORE) {
&& trx->duplicates) {
ulonglong auto_inc;
ulonglong col_max_value;
@ -5429,6 +5427,7 @@ ha_innobase::index_read(
(byte*) key_ptr,
(ulint) key_len,
prebuilt->trx);
DBUG_ASSERT(prebuilt->search_tuple->n_fields > 0);
} else {
/* We position the cursor to the last or the first entry
in the index */
@ -7227,6 +7226,7 @@ ha_innobase::records_in_range(
mem_heap_t* heap;
DBUG_ENTER("records_in_range");
DBUG_ASSERT(min_key || max_key);
ut_a(prebuilt->trx == thd_to_trx(ha_thd()));
@ -7272,6 +7272,9 @@ ha_innobase::records_in_range(
(const uchar*) 0),
(ulint) (min_key ? min_key->length : 0),
prebuilt->trx);
DBUG_ASSERT(min_key
? range_start->n_fields > 0
: range_start->n_fields == 0);
row_sel_convert_mysql_key_to_innobase(
range_end, (byte*) key_val_buff2,
@ -7280,6 +7283,9 @@ ha_innobase::records_in_range(
(const uchar*) 0),
(ulint) (max_key ? max_key->length : 0),
prebuilt->trx);
DBUG_ASSERT(max_key
? range_end->n_fields > 0
: range_end->n_fields == 0);
mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
HA_READ_KEY_EXACT);
@ -8416,6 +8422,7 @@ ha_innobase::extra(
break;
case HA_EXTRA_RESET_STATE:
reset_template(prebuilt);
thd_to_trx(ha_thd())->duplicates = 0;
break;
case HA_EXTRA_NO_KEYREAD:
prebuilt->read_just_key = 0;
@ -8433,19 +8440,18 @@ ha_innobase::extra(
parameters below. We must not invoke update_thd()
either, because the calling threads may change.
CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
case HA_EXTRA_IGNORE_DUP_KEY:
case HA_EXTRA_INSERT_WITH_UPDATE:
thd_to_trx(ha_thd())->duplicates |= TRX_DUP_IGNORE;
break;
case HA_EXTRA_NO_IGNORE_DUP_KEY:
thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_IGNORE;
break;
case HA_EXTRA_WRITE_CAN_REPLACE:
thd_to_trx(ha_thd())->duplicates |= TRX_DUP_REPLACE;
break;
case HA_EXTRA_WRITE_CANNOT_REPLACE:
thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_REPLACE;
break;
case HA_EXTRA_NO_IGNORE_DUP_KEY:
thd_to_trx(ha_thd())->duplicates &=
~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
break;
default:/* Do nothing */
;
}

View File

@ -279,14 +279,6 @@ btr_pcur_commit_specify_mtr(
/*========================*/
btr_pcur_t* pcur, /*!< in: persistent cursor */
mtr_t* mtr); /*!< in: mtr to commit */
/**************************************************************//**
Tests if a cursor is detached: that is the latch mode is BTR_NO_LATCHES.
@return TRUE if detached */
UNIV_INLINE
ibool
btr_pcur_is_detached(
/*=================*/
btr_pcur_t* pcur); /*!< in: persistent cursor */
/*********************************************************//**
Moves the persistent cursor to the next record in the tree. If no records are
left, the cursor stays 'after last in tree'.

View File

@ -415,38 +415,6 @@ btr_pcur_commit_specify_mtr(
pcur->pos_state = BTR_PCUR_WAS_POSITIONED;
}
/**************************************************************//**
Sets the pcur latch mode to BTR_NO_LATCHES. */
UNIV_INLINE
void
btr_pcur_detach(
/*============*/
btr_pcur_t* pcur) /*!< in: persistent cursor */
{
ut_a(pcur->pos_state == BTR_PCUR_IS_POSITIONED);
pcur->latch_mode = BTR_NO_LATCHES;
pcur->pos_state = BTR_PCUR_WAS_POSITIONED;
}
/**************************************************************//**
Tests if a cursor is detached: that is the latch mode is BTR_NO_LATCHES.
@return TRUE if detached */
UNIV_INLINE
ibool
btr_pcur_is_detached(
/*=================*/
btr_pcur_t* pcur) /*!< in: persistent cursor */
{
if (pcur->latch_mode == BTR_NO_LATCHES) {
return(TRUE);
}
return(FALSE);
}
/**************************************************************//**
Sets the old_rec_buf field to NULL. */
UNIV_INLINE

View File

@ -1665,7 +1665,7 @@ row_ins_scan_sec_index_for_duplicate(
ulint n_fields_cmp;
btr_pcur_t pcur;
ulint err = DB_SUCCESS;
unsigned allow_duplicates;
ulint allow_duplicates;
mtr_t mtr;
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
@ -1696,7 +1696,7 @@ row_ins_scan_sec_index_for_duplicate(
btr_pcur_open(index, entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr);
allow_duplicates = thr_get_trx(thr)->duplicates & TRX_DUP_IGNORE;
allow_duplicates = thr_get_trx(thr)->duplicates;
/* Scan index records and check if there is a duplicate */
@ -1830,7 +1830,7 @@ row_ins_duplicate_error_in_clust(
sure that in roll-forward we get the same duplicate
errors as in original execution */
if (trx->duplicates & TRX_DUP_IGNORE) {
if (trx->duplicates) {
/* If the SQL-query will update or replace
duplicate key we will take X-lock for
@ -1874,7 +1874,7 @@ row_ins_duplicate_error_in_clust(
offsets = rec_get_offsets(rec, cursor->index, offsets,
ULINT_UNDEFINED, &heap);
if (trx->duplicates & TRX_DUP_IGNORE) {
if (trx->duplicates) {
/* If the SQL-query will update or replace
duplicate key we will take X-lock for

View File

@ -87,7 +87,12 @@ int mi_close(register MI_INFO *info)
}
#ifdef HAVE_MMAP
if (share->file_map)
_mi_unmap_file(info);
{
if (share->options & HA_OPTION_COMPRESS_RECORD)
_mi_unmap_file(info);
else
mi_munmap_file(info);
}
#endif
if (share->decode_trees)
{

View File

@ -1553,13 +1553,14 @@ my_bool _mi_memmap_file(MI_INFO *info)
void _mi_unmap_file(MI_INFO *info)
{
VOID(my_munmap((char*) info->s->file_map,
(size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN));
DBUG_ASSERT(info->s->options & HA_OPTION_COMPRESS_RECORD);
VOID(my_munmap((char*) info->s->file_map, (size_t) info->s->mmaped_length));
if (myisam_mmap_size != SIZE_T_MAX)
{
pthread_mutex_lock(&THR_LOCK_myisam_mmap);
myisam_mmap_used-= info->s->mmaped_length + MEMMAP_EXTRA_MARGIN;
myisam_mmap_used-= info->s->mmaped_length;
pthread_mutex_unlock(&THR_LOCK_myisam_mmap);
}
}