Merge from mysql-5.5-runtime to mysql-5.5-bugteam.
This commit is contained in:
commit
fbfbc7ee9b
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 \
|
||||
|
10
dbug/dbug.c
10
dbug/dbug.c
@ -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;
|
||||
|
@ -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 *);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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';
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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';
|
||||
|
@ -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 )
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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) */
|
||||
|
@ -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
|
||||
{
|
||||
/*
|
||||
|
13
sql/events.h
13
sql/events.h
@ -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);
|
||||
|
||||
|
34
sql/mdl.cc
34
sql/mdl.cc
@ -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);
|
||||
|
16
sql/mdl.h
16
sql/mdl.h
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
||||
|
168
sql/sql_base.cc
168
sql/sql_base.cc
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)))
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
|
92
sql/table.cc
92
sql/table.cc
@ -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.
|
||||
|
||||
|
13
sql/table.h
13
sql/table.h
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user