Merge from mysql-5.5-runtime to mysql-5.5-bugteam.

This commit is contained in:
Jon Olav Hauglid 2010-10-01 11:23:43 +02:00
commit fbfbc7ee9b
56 changed files with 1368 additions and 566 deletions

View File

@ -220,7 +220,6 @@
#cmakedefine HAVE_PTHREAD_KEY_DELETE 1
#cmakedefine HAVE_PTHREAD_KILL 1
#cmakedefine HAVE_PTHREAD_RWLOCK_RDLOCK 1
#cmakedefine HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP 1
#cmakedefine HAVE_PTHREAD_SETPRIO_NP 1
#cmakedefine HAVE_PTHREAD_SETSCHEDPARAM 1
#cmakedefine HAVE_PTHREAD_SIGMASK 1

View File

@ -346,7 +346,6 @@ CHECK_FUNCTION_EXISTS (pthread_condattr_setclock HAVE_PTHREAD_CONDATTR_SETCLOCK)
CHECK_FUNCTION_EXISTS (pthread_init HAVE_PTHREAD_INIT)
CHECK_FUNCTION_EXISTS (pthread_key_delete HAVE_PTHREAD_KEY_DELETE)
CHECK_FUNCTION_EXISTS (pthread_rwlock_rdlock HAVE_PTHREAD_RWLOCK_RDLOCK)
CHECK_FUNCTION_EXISTS (pthread_rwlockattr_setkind_np HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP)
CHECK_FUNCTION_EXISTS (pthread_sigmask HAVE_PTHREAD_SIGMASK)
CHECK_FUNCTION_EXISTS (pthread_threadmask HAVE_PTHREAD_THREADMASK)
CHECK_FUNCTION_EXISTS (pthread_yield_np HAVE_PTHREAD_YIELD_NP)

View File

@ -2169,7 +2169,7 @@ AC_CHECK_FUNCS(alarm bfill bmove bsearch bzero \
mkstemp mlockall perror poll pread pthread_attr_create mmap mmap64 getpagesize \
pthread_attr_getstacksize pthread_attr_setstacksize pthread_condattr_create \
pthread_getsequence_np pthread_key_delete pthread_rwlock_rdlock \
pthread_rwlockattr_setkind_np pthread_sigmask \
pthread_sigmask \
readlink realpath rename rint rwlock_init setupterm \
shmget shmat shmdt shmctl sigaction sigemptyset sigaddset \
sighold sigset sigthreadmask port_create sleep thr_yield \

View File

@ -515,11 +515,16 @@ int DbugParse(CODE_STATE *cs, const char *control)
stack->maxdepth= stack->next->maxdepth;
stack->sub_level= stack->next->sub_level;
strcpy(stack->name, stack->next->name);
stack->out_file= stack->next->out_file;
stack->prof_file= stack->next->prof_file;
if (stack->next == &init_settings)
{
/* never share with the global parent - it can change under your feet */
/*
Never share with the global parent - it can change under your feet.
Reset out_file to stderr to prevent sharing of trace files between
global and session settings.
*/
stack->out_file= stderr;
stack->functions= ListCopy(init_settings.functions);
stack->p_functions= ListCopy(init_settings.p_functions);
stack->keywords= ListCopy(init_settings.keywords);
@ -527,6 +532,7 @@ int DbugParse(CODE_STATE *cs, const char *control)
}
else
{
stack->out_file= stack->next->out_file;
stack->functions= stack->next->functions;
stack->p_functions= stack->next->p_functions;
stack->keywords= stack->next->keywords;

View File

@ -594,7 +594,7 @@ int my_pthread_fastmutex_lock(my_pthread_fastmutex_t *mp);
/* Use our own version of read/write locks */
#define NEED_MY_RW_LOCK 1
#define rw_lock_t my_rw_lock_t
#define my_rwlock_init(A,B) my_rw_init((A), 0)
#define my_rwlock_init(A,B) my_rw_init((A))
#define rw_rdlock(A) my_rw_rdlock((A))
#define rw_wrlock(A) my_rw_wrlock((A))
#define rw_tryrdlock(A) my_rw_tryrdlock((A))
@ -606,49 +606,82 @@ int my_pthread_fastmutex_lock(my_pthread_fastmutex_t *mp);
#endif /* USE_MUTEX_INSTEAD_OF_RW_LOCKS */
/*
Portable read-write locks which prefer readers.
/**
Portable implementation of special type of read-write locks.
Required by some algorithms in order to provide correctness.
These locks have two properties which are unusual for rwlocks:
1) They "prefer readers" in the sense that they do not allow
situations in which rwlock is rd-locked and there is a
pending rd-lock which is blocked (e.g. due to pending
request for wr-lock).
This is a stronger guarantee than one which is provided for
PTHREAD_RWLOCK_PREFER_READER_NP rwlocks in Linux.
MDL subsystem deadlock detector relies on this property for
its correctness.
2) They are optimized for uncontended wr-lock/unlock case.
This is scenario in which they are most oftenly used
within MDL subsystem. Optimizing for it gives significant
performance improvements in some of tests involving many
connections.
Another important requirement imposed on this type of rwlock
by the MDL subsystem is that it should be OK to destroy rwlock
object which is in unlocked state even though some threads might
have not yet fully left unlock operation for it (of course there
is an external guarantee that no thread will try to lock rwlock
which is destroyed).
Putting it another way the unlock operation should not access
rwlock data after changing its state to unlocked.
TODO/FIXME: We should consider alleviating this requirement as
it blocks us from doing certain performance optimizations.
*/
#if defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && defined(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP)
/*
On systems which have a way to specify that readers should
be preferred through attribute mechanism (e.g. Linux) we use
system implementation of read/write locks.
*/
#define rw_pr_lock_t pthread_rwlock_t
typedef struct st_rw_pr_lock_t {
/**
Lock which protects the structure.
Also held for the duration of wr-lock.
*/
pthread_mutex_t lock;
/**
Condition variable which is used to wake-up
writers waiting for readers to go away.
*/
pthread_cond_t no_active_readers;
/** Number of active readers. */
uint active_readers;
/** Number of writers waiting for readers to go away. */
uint writers_waiting_readers;
/** Indicates whether there is an active writer. */
my_bool active_writer;
#ifdef SAFE_MUTEX
/** Thread holding wr-lock (for debug purposes only). */
pthread_t writer_thread;
#endif
} rw_pr_lock_t;
extern int rw_pr_init(rw_pr_lock_t *);
#define rw_pr_rdlock(A) pthread_rwlock_rdlock(A)
#define rw_pr_wrlock(A) pthread_rwlock_wrlock(A)
#define rw_pr_tryrdlock(A) pthread_rwlock_tryrdlock(A)
#define rw_pr_trywrlock(A) pthread_rwlock_trywrlock(A)
#define rw_pr_unlock(A) pthread_rwlock_unlock(A)
#define rw_pr_destroy(A) pthread_rwlock_destroy(A)
extern int rw_pr_rdlock(rw_pr_lock_t *);
extern int rw_pr_wrlock(rw_pr_lock_t *);
extern int rw_pr_unlock(rw_pr_lock_t *);
extern int rw_pr_destroy(rw_pr_lock_t *);
#ifdef SAFE_MUTEX
#define rw_pr_lock_assert_write_owner(A) \
DBUG_ASSERT((A)->active_writer && pthread_equal(pthread_self(), \
(A)->writer_thread))
#define rw_pr_lock_assert_not_write_owner(A) \
DBUG_ASSERT(! (A)->active_writer || ! pthread_equal(pthread_self(), \
(A)->writer_thread))
#else
#define rw_pr_lock_assert_write_owner(A)
#define rw_pr_lock_assert_not_write_owner(A)
#else
/* Otherwise we have to use our own implementation of read/write locks. */
#define NEED_MY_RW_LOCK 1
struct st_my_rw_lock_t;
#define rw_pr_lock_t my_rw_lock_t
extern int rw_pr_init(struct st_my_rw_lock_t *);
#define rw_pr_rdlock(A) my_rw_rdlock((A))
#define rw_pr_wrlock(A) my_rw_wrlock((A))
#define rw_pr_tryrdlock(A) my_rw_tryrdlock((A))
#define rw_pr_trywrlock(A) my_rw_trywrlock((A))
#define rw_pr_unlock(A) my_rw_unlock((A))
#define rw_pr_destroy(A) my_rw_destroy((A))
#define rw_pr_lock_assert_write_owner(A) my_rw_lock_assert_write_owner((A))
#define rw_pr_lock_assert_not_write_owner(A) my_rw_lock_assert_not_write_owner((A))
#endif /* defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && defined(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) */
#endif /* SAFE_MUTEX */
#ifdef NEED_MY_RW_LOCK
/*
On systems which don't support native read/write locks, or don't support
read/write locks which prefer readers we have to use own implementation.
On systems which don't support native read/write locks we have
to use own implementation.
*/
typedef struct st_my_rw_lock_t {
pthread_mutex_t lock; /* lock for structure */
@ -656,13 +689,12 @@ typedef struct st_my_rw_lock_t {
pthread_cond_t writers; /* waiting writers */
int state; /* -1:writer,0:free,>0:readers */
int waiters; /* number of waiting writers */
my_bool prefer_readers;
#ifdef SAFE_MUTEX
pthread_t write_thread;
#endif
} my_rw_lock_t;
extern int my_rw_init(my_rw_lock_t *, my_bool *);
extern int my_rw_init(my_rw_lock_t *);
extern int my_rw_destroy(my_rw_lock_t *);
extern int my_rw_rdlock(my_rw_lock_t *);
extern int my_rw_wrlock(my_rw_lock_t *);

View File

@ -141,9 +141,7 @@ typedef struct st_mysql_rwlock mysql_rwlock_t;
@c mysql_prlock_t is a drop-in replacement for @c rw_pr_lock_t.
@sa mysql_prlock_init
@sa mysql_prlock_rdlock
@sa mysql_prlock_tryrdlock
@sa mysql_prlock_wrlock
@sa mysql_prlock_trywrlock
@sa mysql_prlock_unlock
@sa mysql_prlock_destroy
*/
@ -420,20 +418,6 @@ typedef struct st_mysql_cond mysql_cond_t;
inline_mysql_rwlock_tryrdlock(RW)
#endif
/**
@def mysql_prlock_tryrdlock(RW)
Instrumented rw_pr_tryrdlock.
@c mysql_prlock_tryrdlock is a drop-in replacement
for @c rw_pr_tryrdlock.
*/
#ifdef HAVE_PSI_INTERFACE
#define mysql_prlock_tryrdlock(RW) \
inline_mysql_prlock_tryrdlock(RW, __FILE__, __LINE__)
#else
#define mysql_prlock_tryrdlock(RW) \
inline_mysql_prlock_tryrdlock(RW)
#endif
/**
@def mysql_rwlock_trywrlock(RW)
Instrumented rwlock_trywrlock.
@ -448,20 +432,6 @@ typedef struct st_mysql_cond mysql_cond_t;
inline_mysql_rwlock_trywrlock(RW)
#endif
/**
@def mysql_prlock_trywrlock(RW)
Instrumented rw_pr_trywrlock.
@c mysql_prlock_trywrlock is a drop-in replacement
for @c rw_pr_trywrlock.
*/
#ifdef HAVE_PSI_INTERFACE
#define mysql_prlock_trywrlock(RW) \
inline_mysql_prlock_trywrlock(RW, __FILE__, __LINE__)
#else
#define mysql_prlock_trywrlock(RW) \
inline_mysql_prlock_trywrlock(RW)
#endif
/**
@def mysql_rwlock_unlock(RW)
Instrumented rwlock_unlock.
@ -905,35 +875,6 @@ static inline int inline_mysql_rwlock_tryrdlock(
return result;
}
#ifndef DISABLE_MYSQL_PRLOCK_H
static inline int inline_mysql_prlock_tryrdlock(
mysql_prlock_t *that
#ifdef HAVE_PSI_INTERFACE
, const char *src_file, uint src_line
#endif
)
{
int result;
#ifdef HAVE_PSI_INTERFACE
struct PSI_rwlock_locker *locker= NULL;
PSI_rwlock_locker_state state;
if (likely(PSI_server && that->m_psi))
{
locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi,
PSI_RWLOCK_TRYREADLOCK);
if (likely(locker != NULL))
PSI_server->start_rwlock_rdwait(locker, src_file, src_line);
}
#endif
result= rw_pr_tryrdlock(&that->m_prlock);
#ifdef HAVE_PSI_INTERFACE
if (likely(locker != NULL))
PSI_server->end_rwlock_rdwait(locker, result);
#endif
return result;
}
#endif
static inline int inline_mysql_rwlock_trywrlock(
mysql_rwlock_t *that
#ifdef HAVE_PSI_INTERFACE
@ -961,35 +902,6 @@ static inline int inline_mysql_rwlock_trywrlock(
return result;
}
#ifndef DISABLE_MYSQL_PRLOCK_H
static inline int inline_mysql_prlock_trywrlock(
mysql_prlock_t *that
#ifdef HAVE_PSI_INTERFACE
, const char *src_file, uint src_line
#endif
)
{
int result;
#ifdef HAVE_PSI_INTERFACE
struct PSI_rwlock_locker *locker= NULL;
PSI_rwlock_locker_state state;
if (likely(PSI_server && that->m_psi))
{
locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi,
PSI_RWLOCK_TRYWRITELOCK);
if (likely(locker != NULL))
PSI_server->start_rwlock_wrwait(locker, src_file, src_line);
}
#endif
result= rw_pr_trywrlock(&that->m_prlock);
#ifdef HAVE_PSI_INTERFACE
if (likely(locker != NULL))
PSI_server->end_rwlock_wrwait(locker, result);
#endif
return result;
}
#endif
static inline int inline_mysql_rwlock_unlock(
mysql_rwlock_t *that)
{

View File

@ -1809,9 +1809,32 @@ CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES (1);
HANDLER t1 OPEN;
# This used to cause the assert
--error ER_NO_SUCH_TABLE
--error ER_NOT_SUPPORTED_YET
HANDLER t1 READ FIRST WHERE f1() = 1;
HANDLER t1 CLOSE;
DROP FUNCTION f1;
DROP TABLE t1;
--echo #
--echo # Bug#54920 Stored functions are allowed in HANDLER statements,
--echo # but broken.
--echo #
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP FUNCTION IF EXISTS f1;
--enable_warnings
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1), (2);
CREATE FUNCTION f1() RETURNS INT RETURN 1;
HANDLER t1 OPEN;
--error ER_NOT_SUPPORTED_YET
HANDLER t1 READ FIRST WHERE f1() = 1;
HANDLER t1 CLOSE;
DROP FUNCTION f1;
DROP TABLE t1;

View File

@ -23,3 +23,19 @@ REPAIR TABLE t1;
Table Op Msg_type Msg_text
test.t1 repair status OK
DROP TABLE t1;
#
# Bug#56422 CHECK TABLE run when the table is locked reports corruption
# along with timeout
#
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INT);
LOCK TABLE t1 WRITE;
# Connection con1
SET lock_wait_timeout= 1;
CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check Error Lock wait timeout exceeded; try restarting transaction
test.t1 check status Operation failed
# Connection default
UNLOCK TABLES;
DROP TABLE t1;

View File

@ -422,3 +422,31 @@ UNLOCK TABLES;
# Connection con1
# Connection default
DROP TABLE t1, t2, t3;
#
# Test for bug #56251 "Deadlock with INSERT DELAYED and MERGE tables".
#
drop table if exists t1, t2, tm;
create table t1(a int);
create table t2(a int);
create table tm(a int) engine=merge union=(t1, t2);
begin;
select * from t1;
a
# Connection 'con1'.
# Sending:
alter table t1 comment 'test';
# Connection 'default'.
# Wait until ALTER TABLE blocks and starts waiting
# for connection 'default'. It should wait with a
# pending SNW lock on 't1'.
# Attempt to perform delayed insert into 'tm' should not lead
# to a deadlock. Instead error ER_DELAYED_NOT_SUPPORTED should
# be emitted.
insert delayed into tm values (1);
ERROR HY000: DELAYED option not supported for table 'tm'
# Unblock ALTER TABLE.
commit;
# Connection 'con1'.
# Reaping ALTER TABLE:
# Connection 'default'.
drop tables tm, t1, t2;

View File

@ -373,3 +373,53 @@ commit;
# --> connection con2
# --> connection default
drop table t1;
#
# Test for bug #55273 "FLUSH TABLE tm WITH READ LOCK for Merge table
# causes assert failure".
#
drop table if exists t1, t2, tm;
create table t1 (i int);
create table t2 (i int);
create table tm (i int) engine=merge union=(t1, t2);
insert into t1 values (1), (2);
insert into t2 values (3), (4);
# The below statement should succeed and lock merge
# table for read. Only merge table gets flushed and
# not underlying tables.
flush tables tm with read lock;
select * from tm;
i
1
2
3
4
# Check that underlying tables are locked.
select * from t1;
i
1
2
select * from t2;
i
3
4
unlock tables;
# This statement should succeed as well and flush
# all tables in the list.
flush tables tm, t1, t2 with read lock;
select * from tm;
i
1
2
3
4
# Naturally, underlying tables should be locked in this case too.
select * from t1;
i
1
2
select * from t2;
i
3
4
unlock tables;
drop tables tm, t1, t2;

View File

@ -1726,7 +1726,22 @@ CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES (1);
HANDLER t1 OPEN;
HANDLER t1 READ FIRST WHERE f1() = 1;
ERROR 42S02: Table 'test.t2' doesn't exist
ERROR 42000: This version of MySQL doesn't yet support 'stored functions in HANDLER ... READ'
HANDLER t1 CLOSE;
DROP FUNCTION f1;
DROP TABLE t1;
#
# Bug#54920 Stored functions are allowed in HANDLER statements,
# but broken.
#
DROP TABLE IF EXISTS t1;
DROP FUNCTION IF EXISTS f1;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1), (2);
CREATE FUNCTION f1() RETURNS INT RETURN 1;
HANDLER t1 OPEN;
HANDLER t1 READ FIRST WHERE f1() = 1;
ERROR 42000: This version of MySQL doesn't yet support 'stored functions in HANDLER ... READ'
HANDLER t1 CLOSE;
DROP FUNCTION f1;
DROP TABLE t1;

View File

@ -1722,7 +1722,22 @@ CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES (1);
HANDLER t1 OPEN;
HANDLER t1 READ FIRST WHERE f1() = 1;
ERROR 42S02: Table 'test.t2' doesn't exist
ERROR 42000: This version of MySQL doesn't yet support 'stored functions in HANDLER ... READ'
HANDLER t1 CLOSE;
DROP FUNCTION f1;
DROP TABLE t1;
#
# Bug#54920 Stored functions are allowed in HANDLER statements,
# but broken.
#
DROP TABLE IF EXISTS t1;
DROP FUNCTION IF EXISTS f1;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1), (2);
CREATE FUNCTION f1() RETURNS INT RETURN 1;
HANDLER t1 OPEN;
HANDLER t1 READ FIRST WHERE f1() = 1;
ERROR 42000: This version of MySQL doesn't yet support 'stored functions in HANDLER ... READ'
HANDLER t1 CLOSE;
DROP FUNCTION f1;
DROP TABLE t1;

View File

@ -17,9 +17,7 @@ mysql.columns_priv OK
mysql.db OK
mysql.event OK
mysql.func OK
mysql.general_log
Error : You can't use locks with log tables.
status : OK
mysql.general_log OK
mysql.help_category OK
mysql.help_keyword OK
mysql.help_relation OK
@ -31,9 +29,7 @@ mysql.proc OK
mysql.procs_priv OK
mysql.renamed_general_log OK
mysql.servers OK
mysql.slow_log
Error : You can't use locks with log tables.
status : OK
mysql.slow_log OK
mysql.tables_priv OK
mysql.time_zone OK
mysql.time_zone_leap_second OK

View File

@ -55,3 +55,11 @@ DROP USER user_1@localhost;
DROP USER USER_1@localhost;
DROP DATABASE db1;
use test;
#
# Extra test coverage for Bug#56595 RENAME TABLE causes assert on OS X
#
CREATE TABLE t1(a INT);
CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a= 1;
RENAME TABLE t1 TO T1;
ALTER TABLE T1 RENAME t1;
DROP TABLE t1;

View File

@ -2913,3 +2913,41 @@ UNLOCK TABLES;
# Connection default
UNLOCK TABLES;
DROP DATABASE db1;
#
# Bug#56292 Deadlock with ALTER TABLE and MERGE tables
#
DROP TABLE IF EXISTS t1, t2, m1;
CREATE TABLE t1(a INT) engine=MyISAM;
CREATE TABLE t2(a INT) engine=MyISAM;
CREATE TABLE m1(a INT) engine=MERGE UNION=(t1, t2);
INSERT INTO t1 VALUES (1), (2);
INSERT INTO t2 VALUES (3), (4);
# Connection con1
SET DEBUG_SYNC= 'mdl_upgrade_shared_lock_to_exclusive SIGNAL upgrade WAIT_FOR continue';
# Sending:
ALTER TABLE m1 engine=MERGE UNION=(t2, t1);
# Connection con2
# Waiting for ALTER TABLE to try lock upgrade
SET DEBUG_SYNC= 'now WAIT_FOR upgrade';
# Sending:
DELETE FROM t2 WHERE a = 3;
# Connection default
# Check that DELETE is waiting on a metadata lock and not a table lock.
# Now that DELETE blocks on a metadata lock, we should be able to do
# SELECT * FROM m1 here. SELECT used to be blocked by a DELETE table
# lock request.
SELECT * FROM m1;
a
1
2
3
4
# Resuming ALTER TABLE
SET DEBUG_SYNC= 'now SIGNAL continue';
# Connection con1
# Reaping: ALTER TABLE m1 engine=MERGE UNION=(t2, t1)
# Connection con2
# Reaping: DELETE FROM t2 WHERE a = 3
# Connection default
DROP TABLE m1, t1, t2;
SET DEBUG_SYNC= 'RESET';

View File

@ -2358,6 +2358,48 @@ t2 WHERE b SOUNDS LIKE e AND d = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
DROP TABLE t2, t1;
#
# Bug#46339 - crash on REPAIR TABLE merge table USE_FRM
#
DROP TABLE IF EXISTS m1, t1;
CREATE TABLE t1 (c1 INT) ENGINE=MYISAM;
CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1) INSERT_METHOD=LAST;
LOCK TABLE m1 READ;
REPAIR TABLE m1 USE_FRM;
Table Op Msg_type Msg_text
test.m1 repair Error Table 'm1' was locked with a READ lock and can't be updated
test.m1 repair status Operation failed
UNLOCK TABLES;
REPAIR TABLE m1 USE_FRM;
Table Op Msg_type Msg_text
test.m1 repair note The storage engine for the table doesn't support repair
DROP TABLE m1,t1;
CREATE TABLE m1 (f1 BIGINT) ENGINE=MRG_MyISAM UNION(t1);
REPAIR TABLE m1 USE_FRM;
Table Op Msg_type Msg_text
test.m1 repair Warning Can't open table
test.m1 repair error Corrupt
CREATE TABLE t1 (f1 BIGINT) ENGINE = MyISAM;
REPAIR TABLE m1 USE_FRM;
Table Op Msg_type Msg_text
test.m1 repair note The storage engine for the table doesn't support repair
REPAIR TABLE m1;
Table Op Msg_type Msg_text
test.m1 repair note The storage engine for the table doesn't support repair
DROP TABLE m1, t1;
CREATE TEMPORARY TABLE m1 (f1 BIGINT) ENGINE=MRG_MyISAM UNION(t1);
REPAIR TABLE m1 USE_FRM;
Table Op Msg_type Msg_text
test.m1 repair Error Table 'test.m1' doesn't exist
test.m1 repair error Corrupt
CREATE TEMPORARY TABLE t1 (f1 BIGINT) ENGINE=MyISAM;
REPAIR TABLE m1 USE_FRM;
Table Op Msg_type Msg_text
m1 repair error Cannot repair temporary table from .frm file
REPAIR TABLE m1;
Table Op Msg_type Msg_text
test.m1 repair note The storage engine for the table doesn't support repair
DROP TABLE m1, t1;
End of 5.1 tests
#
# An additional test case for Bug#27430 Crash in subquery code
@ -2677,7 +2719,7 @@ OPTIMIZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 optimize Error Table 'test.t_not_exists' doesn't exist
test.t1 optimize Error Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
test.t1 optimize note The storage engine for the table doesn't support optimize
test.t1 optimize error Corrupt
DROP TABLE t1;
#
# Bug#36171 - CREATE TEMPORARY TABLE and MERGE engine
@ -3444,13 +3486,12 @@ ALTER TABLE m1 ADD INDEX (c1);
UNLOCK TABLES;
DROP TABLE m1, t1;
#
# If children are to be altered, they need an explicit lock.
# Locking the merge table will implicitly lock children.
#
CREATE TABLE t1 (c1 INT);
CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1);
LOCK TABLE m1 WRITE;
ALTER TABLE t1 ADD INDEX (c1);
ERROR HY000: Table 't1' was locked with a READ lock and can't be updated
LOCK TABLE m1 WRITE, t1 WRITE;
ALTER TABLE t1 ADD INDEX (c1);
UNLOCK TABLES;
@ -3576,4 +3617,48 @@ ERROR HY000: The definition of table 'v1' prevents operation DELETE on table 'm1
drop view v1;
drop temporary table tmp;
drop table t1, t2, t3, m1, m2;
#
# Bug#56494 Segfault in upgrade_shared_lock_to_exclusive() for
# REPAIR of merge table
#
DROP TABLE IF EXISTS t1, t2, t_not_exists;
CREATE TABLE t1(a INT);
ALTER TABLE t1 engine= MERGE UNION (t_not_exists);
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze Error Table 'test.t_not_exists' doesn't exist
test.t1 analyze Error Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
test.t1 analyze error Corrupt
CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check Error Table 'test.t_not_exists' doesn't exist
test.t1 check Error Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
test.t1 check error Corrupt
CHECKSUM TABLE t1;
Table Checksum
test.t1 NULL
Warnings:
Error 1146 Table 'test.t_not_exists' doesn't exist
Error 1168 Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
OPTIMIZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 optimize Error Table 'test.t_not_exists' doesn't exist
test.t1 optimize Error Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
test.t1 optimize error Corrupt
REPAIR TABLE t1;
Table Op Msg_type Msg_text
test.t1 repair Error Table 'test.t_not_exists' doesn't exist
test.t1 repair Error Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
test.t1 repair error Corrupt
REPAIR TABLE t1 USE_FRM;
Table Op Msg_type Msg_text
test.t1 repair Warning Can't open table
test.t1 repair error Corrupt
DROP TABLE t1;
CREATE TABLE t1(a INT);
CREATE TABLE t2(a INT) engine= MERGE UNION (t1);
REPAIR TABLE t2 USE_FRM;
Table Op Msg_type Msg_text
test.t2 repair note The storage engine for the table doesn't support repair
DROP TABLE t1, t2;
End of 6.0 tests

View File

@ -46,14 +46,12 @@ insert into t1 select * from t1;
flush tables;
optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize error Table 'test.t1' is read only
Warnings:
Error 1036 Table 't1' is read only
test.t1 optimize Error Table 't1' is read only
test.t1 optimize status Operation failed
repair table t1;
Table Op Msg_type Msg_text
test.t1 repair error Table 'test.t1' is read only
Warnings:
Error 1036 Table 't1' is read only
test.t1 repair Error Table 't1' is read only
test.t1 repair status Operation failed
drop table t1;
#
# BUG#41541 - Valgrind warnings on packed MyISAM table

View File

@ -5,9 +5,7 @@ mysql.columns_priv OK
mysql.db OK
mysql.event OK
mysql.func OK
mysql.general_log
Error : You can't use locks with log tables.
status : OK
mysql.general_log OK
mysql.help_category OK
mysql.help_keyword OK
mysql.help_relation OK
@ -18,9 +16,7 @@ mysql.plugin OK
mysql.proc OK
mysql.procs_priv OK
mysql.servers OK
mysql.slow_log
Error : You can't use locks with log tables.
status : OK
mysql.slow_log OK
mysql.tables_priv OK
mysql.time_zone OK
mysql.time_zone_leap_second OK
@ -37,9 +33,7 @@ mysql.columns_priv OK
mysql.db OK
mysql.event OK
mysql.func OK
mysql.general_log
Error : You can't use locks with log tables.
status : OK
mysql.general_log OK
mysql.help_category OK
mysql.help_keyword OK
mysql.help_relation OK
@ -50,9 +44,7 @@ mysql.plugin OK
mysql.proc OK
mysql.procs_priv OK
mysql.servers OK
mysql.slow_log
Error : You can't use locks with log tables.
status : OK
mysql.slow_log OK
mysql.tables_priv OK
mysql.time_zone OK
mysql.time_zone_leap_second OK
@ -69,9 +61,7 @@ mysql.columns_priv OK
mysql.db OK
mysql.event OK
mysql.func OK
mysql.general_log
Error : You can't use locks with log tables.
status : OK
mysql.general_log OK
mysql.help_category OK
mysql.help_keyword OK
mysql.help_relation OK
@ -82,9 +72,7 @@ mysql.plugin OK
mysql.proc OK
mysql.procs_priv OK
mysql.servers OK
mysql.slow_log
Error : You can't use locks with log tables.
status : OK
mysql.slow_log OK
mysql.tables_priv OK
mysql.time_zone OK
mysql.time_zone_leap_second OK
@ -103,9 +91,7 @@ mysql.columns_priv OK
mysql.db OK
mysql.event OK
mysql.func OK
mysql.general_log
Error : You can't use locks with log tables.
status : OK
mysql.general_log OK
mysql.help_category OK
mysql.help_keyword OK
mysql.help_relation OK
@ -116,9 +102,7 @@ mysql.plugin OK
mysql.proc OK
mysql.procs_priv OK
mysql.servers OK
mysql.slow_log
Error : You can't use locks with log tables.
status : OK
mysql.slow_log OK
mysql.tables_priv OK
mysql.time_zone OK
mysql.time_zone_leap_second OK
@ -141,9 +125,7 @@ mysql.columns_priv OK
mysql.db OK
mysql.event OK
mysql.func OK
mysql.general_log
Error : You can't use locks with log tables.
status : OK
mysql.general_log OK
mysql.help_category OK
mysql.help_keyword OK
mysql.help_relation OK
@ -154,9 +136,7 @@ mysql.plugin OK
mysql.proc OK
mysql.procs_priv OK
mysql.servers OK
mysql.slow_log
Error : You can't use locks with log tables.
status : OK
mysql.slow_log OK
mysql.tables_priv OK
mysql.time_zone OK
mysql.time_zone_leap_second OK
@ -182,9 +162,7 @@ mysql.columns_priv OK
mysql.db OK
mysql.event OK
mysql.func OK
mysql.general_log
Error : You can't use locks with log tables.
status : OK
mysql.general_log OK
mysql.help_category OK
mysql.help_keyword OK
mysql.help_relation OK
@ -195,9 +173,7 @@ mysql.plugin OK
mysql.proc OK
mysql.procs_priv OK
mysql.servers OK
mysql.slow_log
Error : You can't use locks with log tables.
status : OK
mysql.slow_log OK
mysql.tables_priv OK
mysql.time_zone OK
mysql.time_zone_leap_second OK

View File

@ -7,9 +7,7 @@ mysql.columns_priv OK
mysql.db OK
mysql.event OK
mysql.func OK
mysql.general_log
Error : You can't use locks with log tables.
status : OK
mysql.general_log OK
mysql.help_category OK
mysql.help_keyword OK
mysql.help_relation OK
@ -20,9 +18,7 @@ mysql.plugin OK
mysql.proc OK
mysql.procs_priv OK
mysql.servers OK
mysql.slow_log
Error : You can't use locks with log tables.
status : OK
mysql.slow_log OK
mysql.tables_priv OK
mysql.time_zone OK
mysql.time_zone_leap_second OK

View File

@ -32,3 +32,47 @@ SELECT @@global.debug;
SET GLOBAL debug=@old_debug;
End of 5.1 tests
#
# Bug#46165 server crash in dbug
#
SET @old_globaldebug = @@global.debug;
SET @old_sessiondebug= @@session.debug;
# Test 1 - Bug test case, single connection
SET GLOBAL debug= '+O,../../log/bug46165.1.trace';
SET SESSION debug= '-d:-t:-i';
SET GLOBAL debug= '';
SET SESSION debug= '';
# Test 2 - Bug test case, two connections
# Connection default
SET GLOBAL debug= '+O,../../log/bug46165.2.trace';
SET SESSION debug= '-d:-t:-i';
# Connection con1
SET GLOBAL debug= '';
# Connection default
SET SESSION debug= '';
# Connection con1
# Connection default
SET GLOBAL debug= '';
# Test 3 - Active session trace file on disconnect
# Connection con1
SET GLOBAL debug= '+O,../../log/bug46165.3.trace';
SET SESSION debug= '-d:-t:-i';
SET GLOBAL debug= '';
# Test 4 - Active session trace file on two connections
# Connection default
SET GLOBAL debug= '+O,../../log/bug46165.4.trace';
SET SESSION debug= '-d:-t:-i';
# Connection con1
SET SESSION debug= '-d:-t:-i';
SET GLOBAL debug= '';
SET SESSION debug= '';
# Connection default
SET SESSION debug= '';
# Connection con1
# Connection default
# Test 5 - Different trace files
SET SESSION debug= '+O,../../log/bug46165.5.trace';
SET SESSION debug= '+O,../../log/bug46165.6.trace';
SET SESSION debug= '-O';
SET GLOBAL debug= @old_globaldebug;
SET SESSION debug= @old_sessiondebug;

View File

@ -131,3 +131,14 @@ XA START 'xid1';
XA END 'xid1';
XA ROLLBACK 'xid1';
DROP TABLE t1;
#
# Bug#56448 Assertion failed: ! is_set() with second xa end
#
XA START 'x';
XA END 'x';
XA END 'x';
ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the IDLE state
XA PREPARE 'x';
XA PREPARE 'x';
ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state
XA ROLLBACK 'x';

View File

@ -242,7 +242,7 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction
CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check Error Lock wait timeout exceeded; try restarting transaction
test.t1 check error Corrupt
test.t1 check status Operation failed
UNLOCK TABLES;
DROP TABLE t1;
CREATE TABLE t2 ( i INT NOT NULL AUTO_INCREMENT PRIMARY KEY, f INT )

View File

@ -13,7 +13,7 @@ wait/synch/mutex/sql/LOCK_active_mi YES YES
wait/synch/mutex/sql/LOCK_audit_mask YES YES
wait/synch/mutex/sql/LOCK_connection_count YES YES
wait/synch/mutex/sql/LOCK_crypt YES YES
wait/synch/mutex/sql/LOCK_dd_owns_lock_open YES YES
wait/synch/mutex/sql/LOCK_delayed_create YES YES
select * from performance_schema.SETUP_INSTRUMENTS
where name like 'Wait/Synch/Rwlock/sql/%'
and name not in ('wait/synch/rwlock/sql/CRYPTO_dynlock_value::lock')

View File

@ -53,5 +53,29 @@ REPAIR TABLE t1;
DROP TABLE t1;
--echo #
--echo # Bug#56422 CHECK TABLE run when the table is locked reports corruption
--echo # along with timeout
--echo #
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
CREATE TABLE t1(a INT);
LOCK TABLE t1 WRITE;
--echo # Connection con1
connect(con1, localhost, root);
SET lock_wait_timeout= 1;
CHECK TABLE t1;
--echo # Connection default
connection default;
UNLOCK TABLES;
DROP TABLE t1;
disconnect con1;
# Wait till we reached the initial number of concurrent sessions
--source include/wait_until_count_sessions.inc

View File

@ -552,3 +552,52 @@ disconnect con1;
connection default;
DROP TABLE t1, t2, t3;
--enable_ps_protocol
--echo #
--echo # Test for bug #56251 "Deadlock with INSERT DELAYED and MERGE tables".
--echo #
connect (con1,localhost,root,,);
connection default;
--disable_warnings
drop table if exists t1, t2, tm;
--enable_warnings
create table t1(a int);
create table t2(a int);
create table tm(a int) engine=merge union=(t1, t2);
begin;
select * from t1;
--echo # Connection 'con1'.
connection con1;
--echo # Sending:
--send alter table t1 comment 'test'
--echo # Connection 'default'.
connection default;
--echo # Wait until ALTER TABLE blocks and starts waiting
--echo # for connection 'default'. It should wait with a
--echo # pending SNW lock on 't1'.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table metadata lock" and
info = "alter table t1 comment 'test'";
--source include/wait_condition.inc
--echo # Attempt to perform delayed insert into 'tm' should not lead
--echo # to a deadlock. Instead error ER_DELAYED_NOT_SUPPORTED should
--echo # be emitted.
--error ER_DELAYED_NOT_SUPPORTED
insert delayed into tm values (1);
--echo # Unblock ALTER TABLE.
commit;
--echo # Connection 'con1'.
connection con1;
--echo # Reaping ALTER TABLE:
--reap
disconnect con1;
--source include/wait_until_disconnected.inc
--echo # Connection 'default'.
connection default;
drop tables tm, t1, t2;

View File

@ -546,3 +546,34 @@ disconnect con2;
connection default;
drop table t1;
--echo #
--echo # Test for bug #55273 "FLUSH TABLE tm WITH READ LOCK for Merge table
--echo # causes assert failure".
--echo #
--disable_warnings
drop table if exists t1, t2, tm;
--enable_warnings
create table t1 (i int);
create table t2 (i int);
create table tm (i int) engine=merge union=(t1, t2);
insert into t1 values (1), (2);
insert into t2 values (3), (4);
--echo # The below statement should succeed and lock merge
--echo # table for read. Only merge table gets flushed and
--echo # not underlying tables.
flush tables tm with read lock;
select * from tm;
--echo # Check that underlying tables are locked.
select * from t1;
select * from t2;
unlock tables;
--echo # This statement should succeed as well and flush
--echo # all tables in the list.
flush tables tm, t1, t2 with read lock;
select * from tm;
--echo # Naturally, underlying tables should be locked in this case too.
select * from t1;
select * from t2;
unlock tables;
drop tables tm, t1, t2;

View File

@ -91,3 +91,14 @@ DROP DATABASE db1;
use test;
# End of 5.0 tests
--echo #
--echo # Extra test coverage for Bug#56595 RENAME TABLE causes assert on OS X
--echo #
CREATE TABLE t1(a INT);
CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a= 1;
RENAME TABLE t1 TO T1;
ALTER TABLE T1 RENAME t1;
DROP TABLE t1;

View File

@ -4532,6 +4532,68 @@ disconnect con2;
disconnect con3;
--echo #
--echo # Bug#56292 Deadlock with ALTER TABLE and MERGE tables
--echo #
--disable_warnings
DROP TABLE IF EXISTS t1, t2, m1;
--enable_warnings
CREATE TABLE t1(a INT) engine=MyISAM;
CREATE TABLE t2(a INT) engine=MyISAM;
CREATE TABLE m1(a INT) engine=MERGE UNION=(t1, t2);
INSERT INTO t1 VALUES (1), (2);
INSERT INTO t2 VALUES (3), (4);
connect(con1, localhost, root);
connect(con2, localhost, root);
--echo # Connection con1
connection con1;
SET DEBUG_SYNC= 'mdl_upgrade_shared_lock_to_exclusive SIGNAL upgrade WAIT_FOR continue';
--echo # Sending:
--send ALTER TABLE m1 engine=MERGE UNION=(t2, t1)
--echo # Connection con2
connection con2;
--echo # Waiting for ALTER TABLE to try lock upgrade
SET DEBUG_SYNC= 'now WAIT_FOR upgrade';
--echo # Sending:
--send DELETE FROM t2 WHERE a = 3
--echo # Connection default
connection default;
--echo # Check that DELETE is waiting on a metadata lock and not a table lock.
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Waiting for table metadata lock" AND
info = "DELETE FROM t2 WHERE a = 3";
--source include/wait_condition.inc
--echo # Now that DELETE blocks on a metadata lock, we should be able to do
--echo # SELECT * FROM m1 here. SELECT used to be blocked by a DELETE table
--echo # lock request.
SELECT * FROM m1;
--echo # Resuming ALTER TABLE
SET DEBUG_SYNC= 'now SIGNAL continue';
--echo # Connection con1
connection con1;
--echo # Reaping: ALTER TABLE m1 engine=MERGE UNION=(t2, t1)
--reap
--echo # Connection con2
connection con2;
--echo # Reaping: DELETE FROM t2 WHERE a = 3
--reap
--echo # Connection default
connection default;
DROP TABLE m1, t1, t2;
SET DEBUG_SYNC= 'RESET';
disconnect con1;
disconnect con2;
# Check that all connections opened by test cases in this file are really
# gone so execution of other tests won't be affected by their presence.
--source include/wait_until_count_sessions.inc

View File

@ -2,6 +2,9 @@
# Test of MERGE TABLES
#
# Save the initial number of concurrent sessions.
--source include/count_sessions.inc
# MERGE tables require MyISAM tables
let $default=`select @@global.storage_engine`;
set global storage_engine=myisam;
@ -1731,6 +1734,84 @@ t2 WHERE b SOUNDS LIKE e AND d = 1;
DROP TABLE t2, t1;
--echo #
--echo # Bug#46339 - crash on REPAIR TABLE merge table USE_FRM
--echo #
--disable_warnings
DROP TABLE IF EXISTS m1, t1;
--enable_warnings
#
# Test derived from a proposal of Shane Bester.
#
CREATE TABLE t1 (c1 INT) ENGINE=MYISAM;
CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1) INSERT_METHOD=LAST;
#
# REPAIR ... USE_FRM with LOCK TABLES.
#
LOCK TABLE m1 READ;
REPAIR TABLE m1 USE_FRM;
UNLOCK TABLES;
#
# REPAIR ... USE_FRM without LOCK TABLES.
#
# This statement crashed the server (Bug#46339).
#
REPAIR TABLE m1 USE_FRM;
#
DROP TABLE m1,t1;
#
# Test derived from a proposal of Matthias Leich.
#
# Base table is missing.
#
CREATE TABLE m1 (f1 BIGINT) ENGINE=MRG_MyISAM UNION(t1);
#
# This statement crashed the server (Bug#46339).
#
REPAIR TABLE m1 USE_FRM;
#
# Create base table.
#
CREATE TABLE t1 (f1 BIGINT) ENGINE = MyISAM;
#
# This statement crashed the server (Bug#46339).
#
REPAIR TABLE m1 USE_FRM;
#
# Normal repair as reference.
#
REPAIR TABLE m1;
#
# Cleanup.
#
DROP TABLE m1, t1;
#
# Same with temporary tables.
#
# Base table is missing.
#
CREATE TEMPORARY TABLE m1 (f1 BIGINT) ENGINE=MRG_MyISAM UNION(t1);
#
# This statement crashed the server (Bug#46339).
#
REPAIR TABLE m1 USE_FRM;
#
# Create base table.
#
CREATE TEMPORARY TABLE t1 (f1 BIGINT) ENGINE=MyISAM;
#
# This statement crashed the server (Bug#46339).
#
REPAIR TABLE m1 USE_FRM;
#
# Normal repair as reference.
#
REPAIR TABLE m1;
#
# Cleanup.
#
DROP TABLE m1, t1;
--echo End of 5.1 tests
--echo #
@ -2519,12 +2600,11 @@ UNLOCK TABLES;
DROP TABLE m1, t1;
--echo #
--echo # If children are to be altered, they need an explicit lock.
--echo # Locking the merge table will implicitly lock children.
--echo #
CREATE TABLE t1 (c1 INT);
CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1);
LOCK TABLE m1 WRITE;
--error ER_TABLE_NOT_LOCKED_FOR_WRITE
ALTER TABLE t1 ADD INDEX (c1);
LOCK TABLE m1 WRITE, t1 WRITE;
ALTER TABLE t1 ADD INDEX (c1);
@ -2665,6 +2745,37 @@ drop view v1;
drop temporary table tmp;
drop table t1, t2, t3, m1, m2;
--echo #
--echo # Bug#56494 Segfault in upgrade_shared_lock_to_exclusive() for
--echo # REPAIR of merge table
--echo #
--disable_warnings
DROP TABLE IF EXISTS t1, t2, t_not_exists;
--enable_warnings
CREATE TABLE t1(a INT);
ALTER TABLE t1 engine= MERGE UNION (t_not_exists);
# This caused the segfault
ANALYZE TABLE t1;
CHECK TABLE t1;
CHECKSUM TABLE t1;
OPTIMIZE TABLE t1;
REPAIR TABLE t1;
# This caused an assert
REPAIR TABLE t1 USE_FRM;
DROP TABLE t1;
CREATE TABLE t1(a INT);
CREATE TABLE t2(a INT) engine= MERGE UNION (t1);
# This caused an assert
REPAIR TABLE t2 USE_FRM;
DROP TABLE t1, t2;
--echo End of 6.0 tests
--disable_result_log
@ -2672,3 +2783,7 @@ drop table t1, t2, t3, m1, m2;
eval set global storage_engine=$default;
--enable_result_log
--enable_query_log
# Check that all connections opened by test cases in this file are really
# gone so execution of other tests won't be affected by their presence.
--source include/wait_until_count_sessions.inc

View File

@ -36,3 +36,78 @@ SELECT @@global.debug;
SET GLOBAL debug=@old_debug;
--echo End of 5.1 tests
--echo #
--echo # Bug#46165 server crash in dbug
--echo #
SET @old_globaldebug = @@global.debug;
SET @old_sessiondebug= @@session.debug;
--echo # Test 1 - Bug test case, single connection
SET GLOBAL debug= '+O,../../log/bug46165.1.trace';
SET SESSION debug= '-d:-t:-i';
SET GLOBAL debug= '';
SET SESSION debug= '';
--echo # Test 2 - Bug test case, two connections
--echo # Connection default
connection default;
SET GLOBAL debug= '+O,../../log/bug46165.2.trace';
SET SESSION debug= '-d:-t:-i';
--echo # Connection con1
connect (con1, localhost, root);
SET GLOBAL debug= '';
--echo # Connection default
connection default;
SET SESSION debug= '';
--echo # Connection con1
connection con1;
disconnect con1;
--source include/wait_until_disconnected.inc
--echo # Connection default
connection default;
SET GLOBAL debug= '';
--echo # Test 3 - Active session trace file on disconnect
--echo # Connection con1
connect (con1, localhost, root);
SET GLOBAL debug= '+O,../../log/bug46165.3.trace';
SET SESSION debug= '-d:-t:-i';
SET GLOBAL debug= '';
disconnect con1;
--source include/wait_until_disconnected.inc
--echo # Test 4 - Active session trace file on two connections
--echo # Connection default
connection default;
SET GLOBAL debug= '+O,../../log/bug46165.4.trace';
SET SESSION debug= '-d:-t:-i';
--echo # Connection con1
connect (con1, localhost, root);
SET SESSION debug= '-d:-t:-i';
SET GLOBAL debug= '';
SET SESSION debug= '';
--echo # Connection default
connection default;
SET SESSION debug= '';
--echo # Connection con1
connection con1;
disconnect con1;
--source include/wait_until_disconnected.inc
--echo # Connection default
connection default;
--echo # Test 5 - Different trace files
SET SESSION debug= '+O,../../log/bug46165.5.trace';
SET SESSION debug= '+O,../../log/bug46165.6.trace';
SET SESSION debug= '-O';
SET GLOBAL debug= @old_globaldebug;
SET SESSION debug= @old_sessiondebug;

View File

@ -228,6 +228,23 @@ XA ROLLBACK 'xid1';
disconnect con1;
DROP TABLE t1;
--echo #
--echo # Bug#56448 Assertion failed: ! is_set() with second xa end
--echo #
XA START 'x';
XA END 'x';
# Second XA END caused an assertion.
--error ER_XAER_RMFAIL
XA END 'x';
XA PREPARE 'x';
# Second XA PREPARE also caused an assertion.
--error ER_XAER_RMFAIL
XA PREPARE 'x';
XA ROLLBACK 'x';
# Wait till all disconnects are completed
--source include/wait_until_count_sessions.inc

View File

@ -59,7 +59,7 @@
* Mountain View, California 94043
*/
int my_rw_init(my_rw_lock_t *rwp, my_bool *prefer_readers_attr)
int my_rw_init(my_rw_lock_t *rwp)
{
pthread_condattr_t cond_attr;
@ -74,8 +74,6 @@ int my_rw_init(my_rw_lock_t *rwp, my_bool *prefer_readers_attr)
#ifdef SAFE_MUTEX
rwp->write_thread = 0;
#endif
/* If attribute argument is NULL use default value - prefer writers. */
rwp->prefer_readers= prefer_readers_attr ? *prefer_readers_attr : FALSE;
return(0);
}
@ -96,8 +94,7 @@ int my_rw_rdlock(my_rw_lock_t *rwp)
pthread_mutex_lock(&rwp->lock);
/* active or queued writers */
while (( rwp->state < 0 ) ||
(rwp->waiters && ! rwp->prefer_readers))
while (( rwp->state < 0 ) || rwp->waiters)
pthread_cond_wait( &rwp->readers, &rwp->lock);
rwp->state++;
@ -109,8 +106,7 @@ int my_rw_tryrdlock(my_rw_lock_t *rwp)
{
int res;
pthread_mutex_lock(&rwp->lock);
if ((rwp->state < 0 ) ||
(rwp->waiters && ! rwp->prefer_readers))
if ((rwp->state < 0 ) || rwp->waiters)
res= EBUSY; /* Can't get lock */
else
{
@ -192,30 +188,127 @@ int my_rw_unlock(my_rw_lock_t *rwp)
return(0);
}
#endif /* defined(NEED_MY_RW_LOCK) */
int rw_pr_init(struct st_my_rw_lock_t *rwlock)
{
my_bool prefer_readers_attr= TRUE;
return my_rw_init(rwlock, &prefer_readers_attr);
}
#else
/*
We are on system which has native read/write locks which support
preferring of readers.
*/
int rw_pr_init(rw_pr_lock_t *rwlock)
{
pthread_rwlockattr_t rwlock_attr;
pthread_rwlockattr_init(&rwlock_attr);
pthread_rwlockattr_setkind_np(&rwlock_attr, PTHREAD_RWLOCK_PREFER_READER_NP);
pthread_rwlock_init(rwlock, NULL);
pthread_rwlockattr_destroy(&rwlock_attr);
pthread_mutex_init(&rwlock->lock, NULL);
pthread_cond_init(&rwlock->no_active_readers, NULL);
rwlock->active_readers= 0;
rwlock->writers_waiting_readers= 0;
rwlock->active_writer= FALSE;
#ifdef SAFE_MUTEX
rwlock->writer_thread= 0;
#endif
return 0;
}
#endif /* defined(NEED_MY_RW_LOCK) */
int rw_pr_destroy(rw_pr_lock_t *rwlock)
{
pthread_cond_destroy(&rwlock->no_active_readers);
pthread_mutex_destroy(&rwlock->lock);
return 0;
}
int rw_pr_rdlock(rw_pr_lock_t *rwlock)
{
pthread_mutex_lock(&rwlock->lock);
/*
The fact that we were able to acquire 'lock' mutex means
that there are no active writers and we can acquire rd-lock.
Increment active readers counter to prevent requests for
wr-lock from succeeding and unlock mutex.
*/
rwlock->active_readers++;
pthread_mutex_unlock(&rwlock->lock);
return 0;
}
int rw_pr_wrlock(rw_pr_lock_t *rwlock)
{
pthread_mutex_lock(&rwlock->lock);
if (rwlock->active_readers != 0)
{
/* There are active readers. We have to wait until they are gone. */
rwlock->writers_waiting_readers++;
while (rwlock->active_readers != 0)
pthread_cond_wait(&rwlock->no_active_readers, &rwlock->lock);
rwlock->writers_waiting_readers--;
}
/*
We own 'lock' mutex so there is no active writers.
Also there are no active readers.
This means that we can grant wr-lock.
Not releasing 'lock' mutex until unlock will block
both requests for rd and wr-locks.
Set 'active_writer' flag to simplify unlock.
Thanks to the fact wr-lock/unlock in the absence of
contention from readers is essentially mutex lock/unlock
with a few simple checks make this rwlock implementation
wr-lock optimized.
*/
rwlock->active_writer= TRUE;
#ifdef SAFE_MUTEX
rwlock->writer_thread= pthread_self();
#endif
return 0;
}
int rw_pr_unlock(rw_pr_lock_t *rwlock)
{
if (rwlock->active_writer)
{
/* We are unlocking wr-lock. */
#ifdef SAFE_MUTEX
rwlock->writer_thread= 0;
#endif
rwlock->active_writer= FALSE;
if (rwlock->writers_waiting_readers)
{
/*
Avoid expensive cond signal in case when there is no contention
or it is wr-only.
Note that from view point of performance it would be better to
signal on the condition variable after unlocking mutex (as it
reduces number of contex switches).
Unfortunately this would mean that such rwlock can't be safely
used by MDL subsystem, which relies on the fact that it is OK
to destroy rwlock once it is in unlocked state.
*/
pthread_cond_signal(&rwlock->no_active_readers);
}
pthread_mutex_unlock(&rwlock->lock);
}
else
{
/* We are unlocking rd-lock. */
pthread_mutex_lock(&rwlock->lock);
rwlock->active_readers--;
if (rwlock->active_readers == 0 &&
rwlock->writers_waiting_readers)
{
/*
If we are last reader and there are waiting
writers wake them up.
*/
pthread_cond_signal(&rwlock->no_active_readers);
}
pthread_mutex_unlock(&rwlock->lock);
}
return 0;
}
#endif /* defined(THREAD) */

View File

@ -485,10 +485,7 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
ret= TRUE; // OOM
else if ((ret= db_repository->load_named_event(thd, dbname, name,
new_element)))
{
DBUG_ASSERT(ret == OP_LOAD_ERROR);
delete new_element;
}
else
{
/*

View File

@ -44,19 +44,6 @@ class THD;
typedef class Item COND;
typedef struct charset_info_st CHARSET_INFO;
/* Return codes */
enum enum_events_error_code
{
OP_OK= 0,
OP_NOT_RUNNING,
OP_CANT_KILL,
OP_CANT_INIT,
OP_DISABLED_EVENT,
OP_LOAD_ERROR,
OP_ALREADY_EXISTS
};
int
sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);

View File

@ -124,6 +124,7 @@ public:
Deadlock_detection_visitor(MDL_context *start_node_arg)
: m_start_node(start_node_arg),
m_victim(NULL),
m_current_search_depth(0),
m_found_deadlock(FALSE)
{}
virtual bool enter_node(MDL_context *node);
@ -132,8 +133,6 @@ public:
virtual bool inspect_edge(MDL_context *dest);
MDL_context *get_victim() const { return m_victim; }
void abort_traversal(MDL_context *node);
private:
/**
Change the deadlock victim to a new one if it has lower deadlock
@ -148,6 +147,13 @@ private:
MDL_context *m_start_node;
/** If a deadlock is found, the context that identifies the victim. */
MDL_context *m_victim;
/** Set to the 0 at start. Increased whenever
we descend into another MDL context (aka traverse to the next
wait-for graph node). When MAX_SEARCH_DEPTH is reached, we
assume that a deadlock is found, even if we have not found a
loop.
*/
uint m_current_search_depth;
/** TRUE if we found a deadlock. */
bool m_found_deadlock;
/**
@ -181,7 +187,7 @@ private:
bool Deadlock_detection_visitor::enter_node(MDL_context *node)
{
m_found_deadlock= m_current_search_depth >= MAX_SEARCH_DEPTH;
m_found_deadlock= ++m_current_search_depth >= MAX_SEARCH_DEPTH;
if (m_found_deadlock)
{
DBUG_ASSERT(! m_victim);
@ -201,6 +207,7 @@ bool Deadlock_detection_visitor::enter_node(MDL_context *node)
void Deadlock_detection_visitor::leave_node(MDL_context *node)
{
--m_current_search_depth;
if (m_found_deadlock)
opt_change_victim_to(node);
}
@ -244,21 +251,6 @@ Deadlock_detection_visitor::opt_change_victim_to(MDL_context *new_victim)
}
/**
Abort traversal of a wait-for graph and report a deadlock.
@param node Node which we were about to visit when abort
was initiated.
*/
void Deadlock_detection_visitor::abort_traversal(MDL_context *node)
{
DBUG_ASSERT(! m_victim);
m_found_deadlock= TRUE;
opt_change_victim_to(node);
}
/**
Get a bit corresponding to enum_mdl_type value in a granted/waiting bitmaps
and compatibility matrices.
@ -2064,13 +2056,8 @@ bool MDL_lock::visit_subgraph(MDL_ticket *waiting_ticket,
are visiting it but this is OK: in the worst case we might do some
extra work and one more context might be chosen as a victim.
*/
++gvisitor->m_current_search_depth;
if (gvisitor->enter_node(src_ctx))
{
--gvisitor->m_current_search_depth;
goto end;
}
/*
We do a breadth-first search first -- that is, inspect all
@ -2127,7 +2114,6 @@ bool MDL_lock::visit_subgraph(MDL_ticket *waiting_ticket,
end_leave_node:
gvisitor->leave_node(src_ctx);
--gvisitor->m_current_search_depth;
end:
mysql_prlock_unlock(&m_rwlock);

View File

@ -385,10 +385,7 @@ public:
virtual bool inspect_edge(MDL_context *dest) = 0;
virtual ~MDL_wait_for_graph_visitor();
MDL_wait_for_graph_visitor() :m_lock_open_count(0),
m_current_search_depth(0)
{ }
virtual void abort_traversal(MDL_context *node) = 0;
MDL_wait_for_graph_visitor() :m_lock_open_count(0) {}
public:
/**
XXX, hack: During deadlock search, we may need to
@ -399,17 +396,6 @@ public:
LOCK_open since it has significant performance impacts.
*/
uint m_lock_open_count;
/**
Set to the 0 at start. Increased whenever
we descend into another MDL context (aka traverse to the next
wait-for graph node). When MAX_SEARCH_DEPTH is reached, we
assume that a deadlock is found, even if we have not found a
loop.
XXX: This member belongs to this class only temporarily until
bug #56405 is fixed.
*/
uint m_current_search_depth;
};
/**

View File

@ -4035,7 +4035,8 @@ end:
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
bool any_combination_will_do, uint number, bool no_errors)
{
TABLE_LIST *table, *first_not_own_table= thd->lex->first_not_own_table();
TABLE_LIST *tl;
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
Security_context *sctx= thd->security_ctx;
uint i;
ulong orig_want_access= want_access;
@ -4052,34 +4053,32 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
the given table list refers to the list for prelocking (contains tables
of other queries). For simple queries first_not_own_table is 0.
*/
for (i= 0, table= tables;
i < number && table != first_not_own_table;
table= table->next_global, i++)
for (i= 0, tl= tables;
i < number && tl != first_not_own_table;
tl= tl->next_global, i++)
{
/*
Save a copy of the privileges without the SHOW_VIEW_ACL attribute.
It will be checked during making view.
*/
table->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
tl->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
}
mysql_rwlock_rdlock(&LOCK_grant);
for (table= tables;
table && number-- && table != first_not_own_table;
table= table->next_global)
for (tl= tables;
tl && number-- && tl != first_not_own_table;
tl= tl->next_global)
{
GRANT_TABLE *grant_table;
sctx = test(table->security_ctx) ?
table->security_ctx : thd->security_ctx;
sctx = test(tl->security_ctx) ? tl->security_ctx : thd->security_ctx;
const ACL_internal_table_access *access;
access= get_cached_table_access(&table->grant.m_internal,
table->get_db_name(),
table->get_table_name());
const ACL_internal_table_access *access=
get_cached_table_access(&tl->grant.m_internal,
tl->get_db_name(),
tl->get_table_name());
if (access)
{
switch(access->check(orig_want_access, &table->grant.privilege))
switch(access->check(orig_want_access, &tl->grant.privilege))
{
case ACL_INTERNAL_ACCESS_GRANTED:
/*
@ -4103,29 +4102,33 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
if (!want_access)
continue; // ok
if (!(~table->grant.privilege & want_access) ||
table->is_anonymous_derived_table() || table->schema_table)
if (!(~tl->grant.privilege & want_access) ||
tl->is_anonymous_derived_table() || tl->schema_table)
{
/*
It is subquery in the FROM clause. VIEW set table->derived after
It is subquery in the FROM clause. VIEW set tl->derived after
table opening, but this function always called before table opening.
*/
if (!table->referencing_view)
if (!tl->referencing_view)
{
/*
If it's a temporary table created for a subquery in the FROM
clause, or an INFORMATION_SCHEMA table, drop the request for
a privilege.
*/
table->grant.want_privilege= 0;
tl->grant.want_privilege= 0;
}
continue;
}
if (!(grant_table= table_hash_search(sctx->host, sctx->ip,
table->get_db_name(), sctx->priv_user,
table->get_table_name(), FALSE)))
GRANT_TABLE *grant_table= table_hash_search(sctx->host, sctx->ip,
tl->get_db_name(),
sctx->priv_user,
tl->get_table_name(),
FALSE);
if (!grant_table)
{
want_access &= ~table->grant.privilege;
want_access &= ~tl->grant.privilege;
goto err; // No grants
}
@ -4136,18 +4139,17 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
if (any_combination_will_do)
continue;
table->grant.grant_table=grant_table; // Remember for column test
table->grant.version=grant_version;
table->grant.privilege|= grant_table->privs;
table->grant.want_privilege= ((want_access & COL_ACLS)
& ~table->grant.privilege);
tl->grant.grant_table= grant_table; // Remember for column test
tl->grant.version= grant_version;
tl->grant.privilege|= grant_table->privs;
tl->grant.want_privilege= ((want_access & COL_ACLS) & ~tl->grant.privilege);
if (!(~table->grant.privilege & want_access))
if (!(~tl->grant.privilege & want_access))
continue;
if (want_access & ~(grant_table->cols | table->grant.privilege))
if (want_access & ~(grant_table->cols | tl->grant.privilege))
{
want_access &= ~(grant_table->cols | table->grant.privilege);
want_access &= ~(grant_table->cols | tl->grant.privilege);
goto err; // impossible
}
}
@ -4164,7 +4166,7 @@ err:
command,
sctx->priv_user,
sctx->host_or_ip,
table ? table->get_table_name() : "unknown");
tl ? tl->get_table_name() : "unknown");
}
DBUG_RETURN(TRUE);
}

View File

@ -111,9 +111,6 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
table= &tmp_table;
}
/* A MERGE table must not come here. */
DBUG_ASSERT(table->file->ht->db_type != DB_TYPE_MRG_MYISAM);
/*
REPAIR TABLE ... USE_FRM for temporary tables makes little sense.
*/
@ -151,6 +148,9 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
if (!ext[0] || !ext[1])
goto end; // No data file
/* A MERGE table must not come here. */
DBUG_ASSERT(table->file->ht->db_type != DB_TYPE_MRG_MYISAM);
// Name of data file
strxmov(from, table->s->normalized_path.str, ext[1], NullS);
if (!mysql_file_stat(key_file_misc, from, &stat_info, MYF(0)))
@ -231,6 +231,26 @@ end:
}
/**
Check if a given error is something that could occur during
open_and_lock_tables() that does not indicate table corruption.
@param sql_errno Error number to check.
@retval TRUE Error does not indicate table corruption.
@retval FALSE Error could indicate table corruption.
*/
static inline bool table_not_corrupt_error(uint sql_errno)
{
return (sql_errno == ER_NO_SUCH_TABLE ||
sql_errno == ER_FILE_NOT_FOUND ||
sql_errno == ER_LOCK_WAIT_TIMEOUT ||
sql_errno == ER_LOCK_DEADLOCK ||
sql_errno == ER_CANT_LOCK_LOG_TABLE ||
sql_errno == ER_OPEN_AS_READONLY);
}
/*
RETURN VALUES
@ -311,7 +331,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
lex->query_tables= table;
lex->query_tables_last= &table->next_global;
lex->query_tables_own_last= 0;
thd->no_warnings_for_error= no_warnings_for_error;
/*
Under locked tables, we know that the table can be opened,
so any errors opening the table are logical errors.
In these cases it makes sense to report them.
*/
if (!thd->locked_tables_mode)
thd->no_warnings_for_error= no_warnings_for_error;
if (view_operator_func == NULL)
table->required_type=FRMTYPE_TABLE;
@ -320,6 +346,14 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
table->next_global= save_next_global;
table->next_local= save_next_local;
thd->open_options&= ~extra_open_options;
/*
If open_and_lock_tables() failed, close_thread_tables() will close
the table and table->table can therefore be invalid.
*/
if (open_error)
table->table= NULL;
/*
Under locked tables, we know that the table can be opened,
so any errors opening the table are logical errors.
@ -418,9 +452,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_VIEW_CHECKSUM, ER(ER_VIEW_CHECKSUM));
if (thd->stmt_da->is_error() &&
(thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE ||
thd->stmt_da->sql_errno() == ER_FILE_NOT_FOUND))
/* A missing table is just issued as a failed command */
table_not_corrupt_error(thd->stmt_da->sql_errno()))
result_code= HA_ADMIN_FAILED;
else
/* Default failure code is corrupt table */

View File

@ -13,8 +13,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "sql_parse.h" // check_access,
// check_merge_table_access
#include "sql_parse.h" // check_access
#include "sql_table.h" // mysql_alter_table,
// mysql_exchange_partition
#include "sql_alter.h"
@ -60,11 +59,15 @@ bool Alter_table_statement::execute(THD *thd)
check_access(thd, INSERT_ACL | CREATE_ACL, select_lex->db,
&priv,
NULL, /* Don't use first_tab->grant with sel_lex->db */
0, 0) ||
check_merge_table_access(thd, first_table->db,
create_info.merge_list.first))
0, 0))
DBUG_RETURN(TRUE); /* purecov: inspected */
/* If it is a merge table, check privileges for merge children. */
if (create_info.merge_list.first &&
check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
create_info.merge_list.first, FALSE, UINT_MAX, FALSE))
DBUG_RETURN(TRUE);
if (check_grant(thd, priv_needed, first_table, FALSE, UINT_MAX, FALSE))
DBUG_RETURN(TRUE); /* purecov: inspected */

View File

@ -100,14 +100,11 @@ bool No_such_table_error_handler::safely_trapped_errors()
TABLE_SHAREs, refresh_version and the table id counter.
*/
mysql_mutex_t LOCK_open;
mysql_mutex_t LOCK_dd_owns_lock_open;
uint dd_owns_lock_open= 0;
#ifdef HAVE_PSI_INTERFACE
static PSI_mutex_key key_LOCK_open, key_LOCK_dd_owns_lock_open;
static PSI_mutex_key key_LOCK_open;
static PSI_mutex_info all_tdc_mutexes[]= {
{ &key_LOCK_open, "LOCK_open", PSI_FLAG_GLOBAL },
{ &key_LOCK_dd_owns_lock_open, "LOCK_dd_owns_lock_open", PSI_FLAG_GLOBAL }
{ &key_LOCK_open, "LOCK_open", PSI_FLAG_GLOBAL }
};
/**
@ -250,7 +247,8 @@ static void check_unused(void)
Length of key
*/
uint create_table_def_key(THD *thd, char *key, TABLE_LIST *table_list,
uint create_table_def_key(THD *thd, char *key,
const TABLE_LIST *table_list,
bool tmp_table)
{
uint key_length= (uint) (strmov(strmov(key, table_list->db)+1,
@ -301,8 +299,6 @@ bool table_def_init(void)
init_tdc_psi_keys();
#endif
mysql_mutex_init(key_LOCK_open, &LOCK_open, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_dd_owns_lock_open, &LOCK_dd_owns_lock_open,
MY_MUTEX_INIT_FAST);
oldest_unused_share= &end_of_unused_share;
end_of_unused_share.prev= &oldest_unused_share;
@ -346,7 +342,6 @@ void table_def_free(void)
table_def_inited= 0;
/* Free table definitions. */
my_hash_free(&table_def_cache);
mysql_mutex_destroy(&LOCK_dd_owns_lock_open);
mysql_mutex_destroy(&LOCK_open);
}
DBUG_VOID_RETURN;
@ -1993,39 +1988,60 @@ void update_non_unique_table_error(TABLE_LIST *update,
}
/**
Find temporary table specified by database and table names in the
THD::temporary_tables list.
@return TABLE instance if a temporary table has been found; NULL otherwise.
*/
TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name)
{
TABLE_LIST table_list;
TABLE_LIST tl;
table_list.db= (char*) db;
table_list.table_name= (char*) table_name;
return find_temporary_table(thd, &table_list);
tl.db= (char*) db;
tl.table_name= (char*) table_name;
return find_temporary_table(thd, &tl);
}
TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list)
{
char key[MAX_DBKEY_LENGTH];
uint key_length;
TABLE *table;
DBUG_ENTER("find_temporary_table");
DBUG_PRINT("enter", ("table: '%s'.'%s'",
table_list->db, table_list->table_name));
/**
Find a temporary table specified by TABLE_LIST instance in the
THD::temporary_tables list.
key_length= create_table_def_key(thd, key, table_list, 1);
for (table=thd->temporary_tables ; table ; table= table->next)
@return TABLE instance if a temporary table has been found; NULL otherwise.
*/
TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl)
{
char key[MAX_DBKEY_LENGTH];
uint key_length= create_table_def_key(thd, key, tl, 1);
return find_temporary_table(thd, key, key_length);
}
/**
Find a temporary table specified by a key in the THD::temporary_tables list.
@return TABLE instance if a temporary table has been found; NULL otherwise.
*/
TABLE *find_temporary_table(THD *thd,
const char *table_key,
uint table_key_length)
{
for (TABLE *table= thd->temporary_tables; table; table= table->next)
{
if (table->s->table_cache_key.length == key_length &&
!memcmp(table->s->table_cache_key.str, key, key_length))
if (table->s->table_cache_key.length == table_key_length &&
!memcmp(table->s->table_cache_key.str, table_key, table_key_length))
{
DBUG_PRINT("info",
("Found table. server_id: %u pseudo_thread_id: %lu",
(uint) thd->server_id,
(ulong) thd->variables.pseudo_thread_id));
DBUG_RETURN(table);
return table;
}
}
DBUG_RETURN(0); // Not a temporary table
return NULL;
}
@ -3029,41 +3045,11 @@ retry_share:
table->reginfo.lock_type=TL_READ; /* Assume read */
reset:
DBUG_ASSERT(table->s->ref_count > 0 || table->s->tmp_table != NO_TMP_TABLE);
if (thd->lex->need_correct_ident())
table->alias_name_used= my_strcasecmp(table_alias_charset,
table->s->table_name.str, alias);
/* Fix alias if table name changes */
if (strcmp(table->alias, alias))
{
uint length=(uint) strlen(alias)+1;
table->alias= (char*) my_realloc((char*) table->alias, length,
MYF(MY_WME));
memcpy((char*) table->alias, alias, length);
}
table->tablenr=thd->current_tablenr++;
table->used_fields=0;
table->const_table=0;
table->null_row= table->maybe_null= 0;
table->force_index= table->force_index_order= table->force_index_group= 0;
table->status=STATUS_NO_RECORD;
table->insert_values= 0;
table->fulltext_searched= 0;
table->file->ft_handler= 0;
table->reginfo.impossible_range= 0;
/* Catch wrong handling of the auto_increment_field_not_null. */
DBUG_ASSERT(!table->auto_increment_field_not_null);
table->auto_increment_field_not_null= FALSE;
if (table->timestamp_field)
table->timestamp_field_type= table->timestamp_field->get_auto_set_type();
table->pos_in_table_list= table_list;
table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
table->clear_column_bitmaps();
table_list->table= table;
DBUG_ASSERT(table->key_read == 0);
/* Tables may be reused in a sub statement. */
DBUG_ASSERT(! table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN));
table->init(thd, table_list);
DBUG_RETURN(FALSE);
err_lock:
@ -4536,13 +4522,15 @@ lock_table_names(THD *thd,
! (flags & MYSQL_OPEN_SKIP_TEMPORARY) &&
find_temporary_table(thd, table))))
{
if (schema_set.insert(table))
if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) &&
schema_set.insert(table))
return TRUE;
mdl_requests.push_front(&table->mdl_request);
}
}
if (! mdl_requests.is_empty())
if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) &&
! mdl_requests.is_empty())
{
/*
Scoped locks: Take intention exclusive locks on all involved
@ -5177,6 +5165,8 @@ static bool check_lock_and_start_stmt(THD *thd,
@param[in] lock_type lock to use for table
@param[in] flags options to be used while opening and locking
table (see open_table(), mysql_lock_tables())
@param[in] prelocking_strategy Strategy which specifies how prelocking
algorithm should work for this statement.
@return table
@retval != NULL OK, opened table returned
@ -5202,7 +5192,8 @@ static bool check_lock_and_start_stmt(THD *thd,
*/
TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
thr_lock_type lock_type, uint flags)
thr_lock_type lock_type, uint flags,
Prelocking_strategy *prelocking_strategy)
{
TABLE_LIST *save_next_global;
DBUG_ENTER("open_n_lock_single_table");
@ -5218,7 +5209,8 @@ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
table_l->required_type= FRMTYPE_TABLE;
/* Open the table. */
if (open_and_lock_tables(thd, table_l, FALSE, flags))
if (open_and_lock_tables(thd, table_l, FALSE, flags,
prelocking_strategy))
table_l->table= NULL; /* Just to be sure. */
/* Restore list. */
@ -5710,35 +5702,37 @@ void close_tables_for_reopen(THD *thd, TABLE_LIST **tables,
}
/*
Open a single table without table caching and don't set it in open_list
/**
Open a single table without table caching and don't add it to
THD::open_tables. Depending on the 'add_to_temporary_tables_list' value,
the opened TABLE instance will be addded to THD::temporary_tables list.
SYNPOSIS
open_temporary_table()
thd Thread object
path Path (without .frm)
db database
table_name Table name
link_in_list 1 if table should be linked into thd->temporary_tables
@param thd Thread context.
@param path Path (without .frm)
@param db Database name.
@param table_name Table name.
@param add_to_temporary_tables_list Specifies if the opened TABLE
instance should be linked into
THD::temporary_tables list.
NOTES:
Used by alter_table to open a temporary table and when creating
a temporary table with CREATE TEMPORARY ...
@note This function is used:
- by alter_table() to open a temporary table;
- when creating a temporary table with CREATE TEMPORARY TABLE.
RETURN
0 Error
# TABLE object
@return TABLE instance for opened table.
@retval NULL on error.
*/
TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
const char *table_name, bool link_in_list)
TABLE *open_table_uncached(THD *thd, const char *path, const char *db,
const char *table_name,
bool add_to_temporary_tables_list)
{
TABLE *tmp_table;
TABLE_SHARE *share;
char cache_key[MAX_DBKEY_LENGTH], *saved_cache_key, *tmp_path;
uint key_length;
TABLE_LIST table_list;
DBUG_ENTER("open_temporary_table");
DBUG_ENTER("open_table_uncached");
DBUG_PRINT("enter",
("table: '%s'.'%s' path: '%s' server_id: %u "
"pseudo_thread_id: %lu",
@ -5781,7 +5775,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
share->tmp_table= (tmp_table->file->has_transactions() ?
TRANSACTIONAL_TMP_TABLE : NON_TRANSACTIONAL_TMP_TABLE);
if (link_in_list)
if (add_to_temporary_tables_list)
{
/* growing temp list at the head */
tmp_table->next= thd->temporary_tables;

View File

@ -17,7 +17,6 @@
#define SQL_BASE_INCLUDED
#include "unireg.h" // REQUIRED: for other includes
#include "table.h" /* open_table_mode */
#include "sql_trigger.h" /* trg_event_type */
#include "sql_class.h" /* enum_mark_columns */
#include "mysqld.h" /* key_map */
@ -71,8 +70,6 @@ enum enum_tdc_remove_table_type {TDC_RT_REMOVE_ALL, TDC_RT_REMOVE_NOT_OWN,
bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
extern mysql_mutex_t LOCK_open;
extern mysql_mutex_t LOCK_dd_owns_lock_open;
extern uint dd_owns_lock_open;
bool table_cache_init(void);
void table_cache_free(void);
bool table_def_init(void);
@ -81,7 +78,8 @@ void table_def_start_shutdown(void);
void assign_new_table_id(TABLE_SHARE *share);
uint cached_open_tables(void);
uint cached_table_definitions(void);
uint create_table_def_key(THD *thd, char *key, TABLE_LIST *table_list,
uint create_table_def_key(THD *thd, char *key,
const TABLE_LIST *table_list,
bool tmp_table);
TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
uint key_length, uint db_flags, int *error,
@ -124,6 +122,11 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
(LONG_TIMEOUT = 1 year) rather than the user-supplied timeout value.
*/
#define MYSQL_LOCK_IGNORE_TIMEOUT 0x0800
/**
When acquiring "strong" (SNW, SNRW, X) metadata locks on tables to
be open do not acquire global and schema-scope IX locks.
*/
#define MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK 0x1000
/** Please refer to the internals manual. */
#define MYSQL_OPEN_REOPEN (MYSQL_OPEN_IGNORE_FLUSH |\
@ -143,8 +146,9 @@ bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
bool get_key_map_from_key_list(key_map *map, TABLE *table,
List<String> *index_list);
TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
const char *table_name, bool link_in_list);
TABLE *open_table_uncached(THD *thd, const char *path, const char *db,
const char *table_name,
bool add_to_temporary_tables_list);
TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name);
TABLE *find_write_locked_table(TABLE *list, const char *db,
const char *table_name);
@ -161,7 +165,9 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
const char *db_name,
const char *table_name);
TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name);
TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list);
TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl);
TABLE *find_temporary_table(THD *thd, const char *table_key,
uint table_key_length);
void close_thread_tables(THD *thd);
bool fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
List<Item> &values,
@ -240,7 +246,8 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
int open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, bool derived);
/* simple open_and_lock_tables without derived handling for single table */
TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
thr_lock_type lock_type, uint flags);
thr_lock_type lock_type, uint flags,
Prelocking_strategy *prelocking_strategy);
bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags);
bool lock_tables(THD *thd, TABLE_LIST *tables, uint counter, uint flags);
int decide_logging_format(THD *thd, TABLE_LIST *tables);
@ -449,6 +456,16 @@ open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags)
}
inline TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
thr_lock_type lock_type, uint flags)
{
DML_prelocking_strategy prelocking_strategy;
return open_n_lock_single_table(thd, table_l, lock_type, flags,
&prelocking_strategy);
}
/* open_and_lock_tables with derived handling */
inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
bool derived, uint flags)

View File

@ -634,14 +634,12 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list)
static int
create_insert_stmt_from_insert_delayed(THD *thd, String *buf)
{
/* Append the part of thd->query before "DELAYED" keyword */
if (buf->append(thd->query(),
thd->lex->keyword_delayed_begin - thd->query()))
/* Make a copy of thd->query() and then remove the "DELAYED" keyword */
if (buf->append(thd->query()) ||
buf->replace(thd->lex->keyword_delayed_begin_offset,
thd->lex->keyword_delayed_end_offset -
thd->lex->keyword_delayed_begin_offset, 0))
return 1;
/* Append the part of thd->query after "DELAYED" keyword */
if (buf->append(thd->lex->keyword_delayed_begin + 7))
return 1;
return 0;
}
@ -2495,6 +2493,65 @@ void kill_delayed_threads(void)
}
/**
A strategy for the prelocking algorithm which prevents the
delayed insert thread from opening tables with engines which
do not support delayed inserts.
Particularly it allows to abort open_tables() as soon as we
discover that we have opened a MERGE table, without acquiring
metadata locks on underlying tables.
*/
class Delayed_prelocking_strategy : public Prelocking_strategy
{
public:
virtual bool handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
Sroutine_hash_entry *rt, sp_head *sp,
bool *need_prelocking);
virtual bool handle_table(THD *thd, Query_tables_list *prelocking_ctx,
TABLE_LIST *table_list, bool *need_prelocking);
virtual bool handle_view(THD *thd, Query_tables_list *prelocking_ctx,
TABLE_LIST *table_list, bool *need_prelocking);
};
bool Delayed_prelocking_strategy::
handle_table(THD *thd, Query_tables_list *prelocking_ctx,
TABLE_LIST *table_list, bool *need_prelocking)
{
DBUG_ASSERT(table_list->lock_type == TL_WRITE_DELAYED);
if (!(table_list->table->file->ha_table_flags() & HA_CAN_INSERT_DELAYED))
{
my_error(ER_DELAYED_NOT_SUPPORTED, MYF(0), table_list->table_name);
return TRUE;
}
return FALSE;
}
bool Delayed_prelocking_strategy::
handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
Sroutine_hash_entry *rt, sp_head *sp,
bool *need_prelocking)
{
/* LEX used by the delayed insert thread has no routines. */
DBUG_ASSERT(0);
return FALSE;
}
bool Delayed_prelocking_strategy::
handle_view(THD *thd, Query_tables_list *prelocking_ctx,
TABLE_LIST *table_list, bool *need_prelocking)
{
/* We don't open views in the delayed insert thread. */
DBUG_ASSERT(0);
return FALSE;
}
/**
Open and lock table for use by delayed thread and check that
this table is suitable for delayed inserts.
@ -2505,21 +2562,21 @@ void kill_delayed_threads(void)
bool Delayed_insert::open_and_lock_table()
{
Delayed_prelocking_strategy prelocking_strategy;
/*
Use special prelocking strategy to get ER_DELAYED_NOT_SUPPORTED
error for tables with engines which don't support delayed inserts.
*/
if (!(table= open_n_lock_single_table(&thd, &table_list,
TL_WRITE_DELAYED,
MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK)))
MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK,
&prelocking_strategy)))
{
thd.fatal_error(); // Abort waiting inserts
return TRUE;
}
if (!(table->file->ha_table_flags() & HA_CAN_INSERT_DELAYED))
{
/* To rollback InnoDB statement transaction. */
trans_rollback_stmt(&thd);
my_error(ER_DELAYED_NOT_SUPPORTED, MYF(ME_FATALERROR),
table_list.table_name);
return TRUE;
}
if (table->triggers)
{
/*

View File

@ -2355,15 +2355,19 @@ struct LEX: public Query_tables_list
This pointer is required to add possibly omitted DEFINER-clause to the
DDL-statement before dumping it to the binlog.
keyword_delayed_begin points to the begin of the DELAYED keyword in
INSERT DELAYED statement.
keyword_delayed_begin_offset is the offset to the beginning of the DELAYED
keyword in INSERT DELAYED statement. keyword_delayed_end_offset is the
offset to the character right after the DELAYED keyword.
*/
union {
const char *stmt_definition_begin;
const char *keyword_delayed_begin;
uint keyword_delayed_begin_offset;
};
const char *stmt_definition_end;
union {
const char *stmt_definition_end;
uint keyword_delayed_end_offset;
};
/**
During name resolution search only in the table list given by

View File

@ -177,8 +177,7 @@ static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables)
for (TABLE_LIST *table= tables; table; table= table->next_global)
{
DBUG_ASSERT(table->db && table->table_name);
if (table->updating &&
!find_temporary_table(thd, table->db, table->table_name))
if (table->updating && !find_temporary_table(thd, table))
return 1;
}
return 0;
@ -402,6 +401,7 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_REPAIR]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_OPTIMIZE]|= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_ANALYZE]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_CHECK]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_CREATE_USER]|= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_USER]|= CF_AUTO_COMMIT_TRANS;
@ -415,7 +415,6 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_FLUSH]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_RESET]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_CHECK]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_CREATE_SERVER]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_ALTER_SERVER]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_SERVER]= CF_AUTO_COMMIT_TRANS;
@ -643,45 +642,6 @@ end:
}
/**
@brief Check access privs for a MERGE table and fix children lock types.
@param[in] thd thread handle
@param[in] db database name
@param[in,out] table_list list of child tables (merge_list)
lock_type and optionally db set per table
@return status
@retval 0 OK
@retval != 0 Error
@detail
This function is used for write access to MERGE tables only
(CREATE TABLE, ALTER TABLE ... UNION=(...)). Set TL_WRITE for
every child. Set 'db' for every child if not present.
*/
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list)
{
int error= 0;
if (table_list)
{
/* Check that all tables use the current database */
TABLE_LIST *tlist;
for (tlist= table_list; tlist; tlist= tlist->next_local)
{
if (!tlist->db || !tlist->db[0])
tlist->db= db; /* purecov: inspected */
}
error= check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
table_list, FALSE, UINT_MAX, FALSE);
}
return error;
}
#endif
/* This works because items are allocated with sql_alloc() */
void free_items(Item *item)
@ -6964,10 +6924,16 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
if (check_access(thd, want_priv, create_table->db,
&create_table->grant.privilege,
&create_table->grant.m_internal,
0, 0) ||
check_merge_table_access(thd, create_table->db,
lex->create_info.merge_list.first))
0, 0))
goto err;
/* If it is a merge table, check privileges for merge children. */
if (lex->create_info.merge_list.first &&
check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
lex->create_info.merge_list.first,
FALSE, UINT_MAX, FALSE))
goto err;
if (want_priv != CREATE_TMP_ACL &&
check_grant(thd, want_priv, create_table, FALSE, 1, FALSE))
goto err;

View File

@ -153,7 +153,6 @@ bool check_single_table_access(THD *thd, ulong privilege,
bool check_routine_access(THD *thd,ulong want_access,char *db,char *name,
bool is_proc, bool no_errors);
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list);
bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc);
bool check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
GRANT_INTERNAL_INFO *grant_internal_info,
@ -176,8 +175,6 @@ inline bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
table->grant.privilege= want_access;
return false;
}
inline bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list)
{ return false; }
inline bool check_some_routine_access(THD *thd, const char *db,
const char *name, bool is_proc)
{ return false; }

View File

@ -328,7 +328,6 @@ bool reload_acl_and_cache(THD *thd, unsigned long options,
-------------------------------------
- you can't flush WITH READ LOCK a non-existent table
- you can't flush WITH READ LOCK under LOCK TABLES
- currently incompatible with the GRL (@todo: fix)
Effect on views and temporary tables.
------------------------------------
@ -338,6 +337,13 @@ bool reload_acl_and_cache(THD *thd, unsigned long options,
if there is a base table, it's used, otherwise ER_NO_SUCH_TABLE
is returned.
Handling of MERGE tables
------------------------
For MERGE table this statement will open and lock child tables
for read (it is impossible to lock parent table without it).
Child tables won't be flushed unless they are explicitly present
in the statement's table list.
Implicit commit
---------------
This statement causes an implicit commit before and
@ -354,7 +360,6 @@ bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
{
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
TABLE_LIST *table_list;
MDL_request_list mdl_requests;
/*
This is called from SQLCOM_FLUSH, the transaction has
@ -368,17 +373,13 @@ bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
}
/*
Acquire SNW locks on tables to be flushed. We can't use
lock_table_names() here as this call will also acquire global IX
and database-scope IX locks on the tables, and this will make
Acquire SNW locks on tables to be flushed. Don't acquire global
IX and database-scope IX locks on the tables as this will make
this statement incompatible with FLUSH TABLES WITH READ LOCK.
*/
for (table_list= all_tables; table_list;
table_list= table_list->next_global)
mdl_requests.push_front(&table_list->mdl_request);
if (thd->mdl_context.acquire_locks(&mdl_requests,
thd->variables.lock_wait_timeout))
if (lock_table_names(thd, all_tables, NULL,
thd->variables.lock_wait_timeout,
MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK))
goto error;
DEBUG_SYNC(thd,"flush_tables_with_read_lock_after_acquire_locks");
@ -390,21 +391,24 @@ bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
table_list->db,
table_list->table_name, FALSE);
/* Skip views and temporary tables. */
table_list->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */
table_list->open_type= OT_BASE_ONLY; /* Ignore temporary tables. */
/* Reset ticket to satisfy asserts in open_tables(). */
table_list->mdl_request.ticket= NULL;
}
/*
Before opening and locking tables the below call also waits
for old shares to go away, so the fact that we don't pass
MYSQL_LOCK_IGNORE_FLUSH flag to it is important.
Also we don't pass MYSQL_OPEN_HAS_MDL_LOCK flag as we want
to open underlying tables if merge table is flushed.
For underlying tables of the merge the below call has to
acquire SNW locks to ensure that they can be locked for
read without further waiting.
*/
if (open_and_lock_tables(thd, all_tables, FALSE,
MYSQL_OPEN_HAS_MDL_LOCK,
&lock_tables_prelocking_strategy) ||
thd->locked_tables_list.init_locked_tables(thd))
if (open_and_lock_tables(thd, all_tables, FALSE,
MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK,
&lock_tables_prelocking_strategy) ||
thd->locked_tables_list.init_locked_tables(thd))
{
goto error;
}

View File

@ -285,6 +285,7 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name,
{
if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db,
old_alias,
ren_table->table_name,
new_db,
new_alias)))
{

View File

@ -22,7 +22,7 @@
#include "sql_rename.h" // do_rename
#include "sql_parse.h" // test_if_data_home_dir
#include "sql_cache.h" // query_cache_*
#include "sql_base.h" // open_temporary_table, lock_table_names
#include "sql_base.h" // open_table_uncached, lock_table_names
#include "lock.h" // wait_if_global_read_lock
// start_waiting_global_read_lock,
// mysql_unlock_tables
@ -2008,7 +2008,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
{
for (table= tables; table; table= table->next_local)
if (table->open_type != OT_BASE_ONLY &&
find_temporary_table(thd, table->db, table->table_name))
find_temporary_table(thd, table))
{
/*
A temporary table.
@ -4225,9 +4225,14 @@ bool mysql_create_table_no_lock(THD *thd,
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
TABLE *table= NULL;
/* Open table and put in temporary table list */
if (!(table= open_temporary_table(thd, path, db, table_name, 1)))
/*
Open a table (skipping table cache) and add it into
THD::temporary_tables list.
*/
TABLE *table= open_table_uncached(thd, path, db, table_name, TRUE);
if (!table)
{
(void) rm_temporary_table(create_info->db_type, path);
goto err;
@ -5914,7 +5919,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
*fn_ext(new_name)=0;
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
error= -1;
else if (Table_triggers_list::change_table_name(thd, db, table_name,
else if (Table_triggers_list::change_table_name(thd, db,
alias, table_name,
new_db, new_alias))
{
(void) mysql_rename_table(old_db_type, new_db, new_alias, db,
@ -6302,8 +6308,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
/* table is a normal table: Create temporary table in same directory */
build_table_filename(path, sizeof(path) - 1, new_db, tmp_name, "",
FN_IS_TMP);
/* Open our intermediate table */
new_table= open_temporary_table(thd, path, new_db, tmp_name, 1);
/* Open our intermediate table. */
new_table= open_table_uncached(thd, path, new_db, tmp_name, TRUE);
}
if (!new_table)
goto err_new_table_cleanup;
@ -6551,7 +6557,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
(need_copy_table != ALTER_TABLE_METADATA_ONLY ||
mysql_rename_table(save_old_db_type, db, table_name, new_db,
new_alias, NO_FRM_RENAME)) &&
Table_triggers_list::change_table_name(thd, db, table_name,
Table_triggers_list::change_table_name(thd, db, alias, table_name,
new_db, new_alias)))
{
/* Try to get everything back. */
@ -6643,7 +6649,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
char path[FN_REFLEN];
TABLE *t_table;
build_table_filename(path + 1, sizeof(path) - 1, new_db, table_name, "", 0);
t_table= open_temporary_table(thd, path, new_db, tmp_name, 0);
t_table= open_table_uncached(thd, path, new_db, tmp_name, FALSE);
if (t_table)
{
intern_close_table(t_table);

View File

@ -458,7 +458,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DBUG_ASSERT(tables->next_global == 0);
/* We do not allow creation of triggers on temporary tables. */
if (create && find_temporary_table(thd, tables->db, tables->table_name))
if (create && find_temporary_table(thd, tables))
{
my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias);
goto end;
@ -1874,6 +1874,7 @@ Table_triggers_list::change_table_name_in_trignames(const char *old_db_name,
@param[in,out] thd Thread context
@param[in] db Old database of subject table
@param[in] old_alias Old alias of subject table
@param[in] old_table Old name of subject table
@param[in] new_db New database for subject table
@param[in] new_table New name of subject table
@ -1890,6 +1891,7 @@ Table_triggers_list::change_table_name_in_trignames(const char *old_db_name,
*/
bool Table_triggers_list::change_table_name(THD *thd, const char *db,
const char *old_alias,
const char *old_table,
const char *new_db,
const char *new_table)
@ -1911,7 +1913,7 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db,
MDL_EXCLUSIVE));
DBUG_ASSERT(my_strcasecmp(table_alias_charset, db, new_db) ||
my_strcasecmp(table_alias_charset, old_table, new_table));
my_strcasecmp(table_alias_charset, old_alias, new_table));
if (Table_triggers_list::check_n_load(thd, db, old_table, &table, TRUE))
{
@ -1920,7 +1922,7 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db,
}
if (table.triggers)
{
LEX_STRING old_table_name= { (char *) old_table, strlen(old_table) };
LEX_STRING old_table_name= { (char *) old_alias, strlen(old_alias) };
LEX_STRING new_table_name= { (char *) new_table, strlen(new_table) };
/*
Since triggers should be in the same schema as their subject tables

View File

@ -157,6 +157,7 @@ public:
TABLE *table, bool names_only);
static bool drop_all_triggers(THD *thd, char *db, char *table_name);
static bool change_table_name(THD *thd, const char *db,
const char *old_alias,
const char *old_table,
const char *new_db,
const char *new_table);

View File

@ -208,8 +208,8 @@ static bool recreate_temporary_table(THD *thd, TABLE *table)
ha_create_table(thd, share->normalized_path.str, share->db.str,
share->table_name.str, &create_info, 1);
if (open_temporary_table(thd, share->path.str, share->db.str,
share->table_name.str, 1))
if (open_table_uncached(thd, share->path.str, share->db.str,
share->table_name.str, TRUE))
{
error= FALSE;
thd->thread_specific_used= TRUE;

View File

@ -10447,7 +10447,10 @@ insert_lock_option:
| LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }
| DELAYED_SYM
{
Lex->keyword_delayed_begin= YYLIP->get_tok_start();
Lex->keyword_delayed_begin_offset= (uint)(YYLIP->get_tok_start() -
YYTHD->query());
Lex->keyword_delayed_end_offset= Lex->keyword_delayed_begin_offset +
YYLIP->yyLength() + 1;
$$= TL_WRITE_DELAYED;
}
| HIGH_PRIORITY { $$= TL_WRITE; }
@ -10457,7 +10460,10 @@ replace_lock_option:
opt_low_priority { $$= $1; }
| DELAYED_SYM
{
Lex->keyword_delayed_begin= YYLIP->get_tok_start();
Lex->keyword_delayed_begin_offset= (uint)(YYLIP->get_tok_start() -
YYTHD->query());
Lex->keyword_delayed_end_offset= Lex->keyword_delayed_begin_offset +
YYLIP->yyLength() + 1;
$$= TL_WRITE_DELAYED;
}
;
@ -11278,7 +11284,11 @@ opt_with_read_lock:
TABLE_LIST *tables= Lex->query_tables;
Lex->type|= REFRESH_READ_LOCK;
for (; tables; tables= tables->next_global)
{
tables->mdl_request.set_type(MDL_SHARED_NO_WRITE);
tables->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */
tables->open_type= OT_BASE_ONLY; /* Ignore temporary tables. */
}
}
;
@ -13241,6 +13251,13 @@ handler:
handler_read_or_scan where_clause opt_limit_clause
{
Lex->expr_allows_subselect= TRUE;
/* Stored functions are not supported for HANDLER READ. */
if (Lex->uses_stored_routines())
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"stored functions in HANDLER ... READ");
MYSQL_YYABORT;
}
}
;

View File

@ -3085,30 +3085,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
holding a write-lock on MDL_lock::m_rwlock.
*/
if (gvisitor->m_lock_open_count++ == 0)
{
/*
To circumvent bug #56405 "Deadlock in the MDL deadlock detector"
we don't try to lock LOCK_open mutex if some thread doing
deadlock detection already owns it and current search depth is
greater than 0. Instead we report a deadlock.
TODO/FIXME: The proper fix for this bug is to use rwlocks for
protection of table shares/instead of LOCK_open.
Unfortunately it requires more effort/has significant
performance effect.
*/
mysql_mutex_lock(&LOCK_dd_owns_lock_open);
if (gvisitor->m_current_search_depth > 0 && dd_owns_lock_open > 0)
{
mysql_mutex_unlock(&LOCK_dd_owns_lock_open);
--gvisitor->m_lock_open_count;
gvisitor->abort_traversal(src_ctx);
return TRUE;
}
++dd_owns_lock_open;
mysql_mutex_unlock(&LOCK_dd_owns_lock_open);
mysql_mutex_lock(&LOCK_open);
}
I_P_List_iterator <TABLE, TABLE_share> tables_it(used_tables);
@ -3123,12 +3100,8 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
goto end;
}
++gvisitor->m_current_search_depth;
if (gvisitor->enter_node(src_ctx))
{
--gvisitor->m_current_search_depth;
goto end;
}
while ((table= tables_it++))
{
@ -3151,16 +3124,10 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
end_leave_node:
gvisitor->leave_node(src_ctx);
--gvisitor->m_current_search_depth;
end:
if (gvisitor->m_lock_open_count-- == 1)
{
mysql_mutex_unlock(&LOCK_open);
mysql_mutex_lock(&LOCK_dd_owns_lock_open);
--dd_owns_lock_open;
mysql_mutex_unlock(&LOCK_dd_owns_lock_open);
}
return result;
}
@ -3256,6 +3223,65 @@ bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime,
}
/**
Initialize TABLE instance (newly created, or coming either from table
cache or THD::temporary_tables list) and prepare it for further use
during statement execution. Set the 'alias' attribute from the specified
TABLE_LIST element. Remember the TABLE_LIST element in the
TABLE::pos_in_table_list member.
@param thd Thread context.
@param tl TABLE_LIST element.
*/
void TABLE::init(THD *thd, TABLE_LIST *tl)
{
DBUG_ASSERT(s->ref_count > 0 || s->tmp_table != NO_TMP_TABLE);
if (thd->lex->need_correct_ident())
alias_name_used= my_strcasecmp(table_alias_charset,
s->table_name.str,
tl->alias);
/* Fix alias if table name changes. */
if (strcmp(alias, tl->alias))
{
uint length= (uint) strlen(tl->alias)+1;
alias= (char*) my_realloc((char*) alias, length, MYF(MY_WME));
memcpy((char*) alias, tl->alias, length);
}
tablenr= thd->current_tablenr++;
used_fields= 0;
const_table= 0;
null_row= 0;
maybe_null= 0;
force_index= 0;
force_index_order= 0;
force_index_group= 0;
status= STATUS_NO_RECORD;
insert_values= 0;
fulltext_searched= 0;
file->ft_handler= 0;
reginfo.impossible_range= 0;
/* Catch wrong handling of the auto_increment_field_not_null. */
DBUG_ASSERT(!auto_increment_field_not_null);
auto_increment_field_not_null= FALSE;
if (timestamp_field)
timestamp_field_type= timestamp_field->get_auto_set_type();
pos_in_table_list= tl;
clear_column_bitmaps();
DBUG_ASSERT(key_read == 0);
/* Tables may be reused in a sub statement. */
DBUG_ASSERT(!file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN));
}
/*
Create Item_field for each column in the table.

View File

@ -83,18 +83,6 @@ enum enum_table_ref_type
};
/**
Opening modes for open_temporary_table and open_table_from_share
*/
enum open_table_mode
{
OTM_OPEN= 0,
OTM_CREATE= 1,
OTM_ALTER= 2
};
/*************************************************************************/
/**
@ -1096,6 +1084,7 @@ public:
#endif
MDL_ticket *mdl_ticket;
void init(THD *thd, TABLE_LIST *tl);
bool fill_item_list(List<Item> *item_list) const;
void reset_item_list(List<Item> *item_list) const;
void clear_column_bitmaps(void);

View File

@ -565,7 +565,8 @@ bool trans_xa_end(THD *thd)
else if (!xa_trans_rolled_back(&thd->transaction.xid_state))
thd->transaction.xid_state.xa_state= XA_IDLE;
DBUG_RETURN(thd->transaction.xid_state.xa_state != XA_IDLE);
DBUG_RETURN(thd->is_error() ||
thd->transaction.xid_state.xa_state != XA_IDLE);
}
@ -596,7 +597,8 @@ bool trans_xa_prepare(THD *thd)
else
thd->transaction.xid_state.xa_state= XA_PREPARED;
DBUG_RETURN(thd->transaction.xid_state.xa_state != XA_PREPARED);
DBUG_RETURN(thd->is_error() ||
thd->transaction.xid_state.xa_state != XA_PREPARED);
}

View File

@ -478,6 +478,8 @@ int ha_myisammrg::add_children_list(void)
/* Set the expected table version, to not cause spurious re-prepare. */
child_l->set_table_ref_id(mrg_child_def->get_child_table_ref_type(),
mrg_child_def->get_child_def_version());
/* Use the same metadata lock type for children. */
child_l->mdl_request.set_type(parent_l->mdl_request.type);
/* Link TABLE_LIST object into the children list. */
if (this->children_last_l)
child_l->prev_global= this->children_last_l;