diff --git a/mysql-test/r/lock.result b/mysql-test/r/lock.result index 8f680858fdc..348412ea441 100644 --- a/mysql-test/r/lock.result +++ b/mysql-test/r/lock.result @@ -356,5 +356,18 @@ ERROR HY000: Can't execute the given command because you have active locked tabl UNLOCK TABLES; DROP TABLE t1; # +# Simplified test for bug #48538 "Assertion in thr_lock() on LOAD DATA +# CONCURRENT INFILE". +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (f1 INT, f2 INT) ENGINE = MEMORY; +CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW +UPDATE LOW_PRIORITY t1 SET f2 = 7; +# Statement below should fail with ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG +# error instead of failing on assertion in table-level locking subsystem. +INSERT INTO t1(f1) VALUES(0); +ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. +DROP TABLE t1; +# # End of 6.0 tests. # diff --git a/mysql-test/t/lock.test b/mysql-test/t/lock.test index 64003c9d861..49e98abdc76 100644 --- a/mysql-test/t/lock.test +++ b/mysql-test/t/lock.test @@ -441,6 +441,28 @@ FLUSH TABLES WITH READ LOCK; UNLOCK TABLES; DROP TABLE t1; + +--echo # +--echo # Simplified test for bug #48538 "Assertion in thr_lock() on LOAD DATA +--echo # CONCURRENT INFILE". +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (f1 INT, f2 INT) ENGINE = MEMORY; +CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW + UPDATE LOW_PRIORITY t1 SET f2 = 7; + +--echo # Statement below should fail with ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG +--echo # error instead of failing on assertion in table-level locking subsystem. +--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG +INSERT INTO t1(f1) VALUES(0); + +DROP TABLE t1; + + --echo # --echo # End of 6.0 tests. --echo # diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index a3f3e9ee080..a6bc128f32a 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -674,14 +674,23 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, write locks are of TL_WRITE_ALLOW_WRITE type. Note that, since lock requests for the same table are sorted in - such way that requests with higher thr_lock_type value come first, - lock being requested usually has equal or "weaker" type than one - which thread might have already acquired. - The exceptions are situations when: - - old lock type is TL_WRITE_ALLOW_READ and new lock type is - TL_WRITE_ALLOW_WRITE - - when old lock type is TL_WRITE_DELAYED - But these should never happen within MySQL. + such way that requests with higher thr_lock_type value come first + (with one exception (*)), lock being requested usually (**) has + equal or "weaker" type than one which thread might have already + acquired. + *) The only exception to this rule is case when type of old lock + is TL_WRITE_LOW_PRIORITY and type of new lock is changed inside + of thr_lock() from TL_WRITE_CONCURRENT_INSERT to TL_WRITE since + engine turns out to be not supporting concurrent inserts. + Note that since TL_WRITE has the same compatibility rules as + TL_WRITE_LOW_PRIORITY (their only difference is priority), + it is OK to grant new lock without additional checks in such + situation. + **) The exceptions are situations when: + - old lock type is TL_WRITE_ALLOW_READ and new lock type is + TL_WRITE_ALLOW_WRITE + - when old lock type is TL_WRITE_DELAYED + But these should never happen within MySQL. Therefore it is OK to allow acquiring write lock on the table if this thread already holds some write lock on it. @@ -690,7 +699,9 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, different types of write lock on the same table). */ DBUG_ASSERT(! has_old_lock(lock->write.data, data->owner) || - (lock_type <= lock->write.data->type && + ((lock_type <= lock->write.data->type || + (lock_type == TL_WRITE && + lock->write.data->type == TL_WRITE_LOW_PRIORITY)) && ! ((lock_type < TL_WRITE_ALLOW_READ && lock->write.data->type == TL_WRITE_ALLOW_READ) || lock->write.data->type == TL_WRITE_DELAYED)));