Skip to content

Commit 0ec868c

Browse files
author
Dmitry Lenev
committed
Fix for bug #50908 "Assertion `handler_tables_hash.records == 0'
failed in enter_locked_tables_mode". Server was aborted due to assertion failure when one tried to execute statement requiring prelocking (i.e. firing triggers or using stored functions) while having open HANDLERs. The problem was that THD::enter_locked_tables_mode() method which was called at the beginning of execution of prelocked statement assumed there are no open HANDLERs. It had to do so because corresponding THD::leave_locked_tables_mode() method was unable to properly restore MDL sentinel when leaving LOCK TABLES/prelocked mode in the presence of open HANDLERs. This patch solves this problem by changing the latter method to properly restore MDL sentinel and thus removing need for this assumption. As a side-effect, it lifts unjustified limitation by allowing to keep HANDLERs open when entering LOCK TABLES mode.
1 parent bca1fec commit 0ec868c

File tree

8 files changed

+580
-59
lines changed

8 files changed

+580
-59
lines changed

mysql-test/include/handler.inc

Lines changed: 151 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -804,12 +804,10 @@ handler t1 open;
804804
handler t2 open;
805805
handler t3 open;
806806
--echo #
807-
--echo # LOCK TABLES implicitly closes all handlers.
808-
--echo #
809-
lock table t3 read;
810-
--echo #
811-
--echo # No HANDLER sql is available under lock tables anyway.
807+
--echo # No HANDLER sql is allowed under LOCK TABLES.
808+
--echo # But it does not implicitly closes all handlers.
812809
--echo #
810+
lock table t1 read;
813811
--error ER_LOCK_OR_ACTIVE_TRANSACTION
814812
handler t1 open;
815813
--error ER_LOCK_OR_ACTIVE_TRANSACTION
@@ -818,18 +816,18 @@ handler t1 read next;
818816
handler t2 close;
819817
--error ER_LOCK_OR_ACTIVE_TRANSACTION
820818
handler t3 open;
821-
--echo # After UNLOCK TABLES no handlers are around, they were
822-
--echo # implicitly closed.
819+
--echo # After UNLOCK TABLES handlers should be around and
820+
--echo # we should be able to continue reading through them.
823821
unlock tables;
824-
drop temporary table t3;
825-
--error ER_UNKNOWN_TABLE
826822
handler t1 read next;
827-
--error ER_UNKNOWN_TABLE
823+
handler t1 close;
824+
handler t2 read next;
828825
handler t2 close;
829-
--error ER_UNKNOWN_TABLE
830826
handler t3 read next;
827+
handler t3 close;
828+
drop temporary table t3;
831829
--echo #
832-
--echo # Other operations also implicitly close handler:
830+
--echo # Other operations that implicitly close handler:
833831
--echo #
834832
--echo # TRUNCATE
835833
--echo #
@@ -922,6 +920,93 @@ handler t1 read a prev;
922920
handler t1 close;
923921
unlock tables;
924922
--echo #
923+
--echo # Let us also check that these operations behave in similar
924+
--echo # way under LOCK TABLES.
925+
--echo #
926+
--echo # TRUNCATE under LOCK TABLES.
927+
--echo #
928+
handler t1 open;
929+
lock tables t1 write;
930+
truncate table t1;
931+
unlock tables;
932+
--error ER_UNKNOWN_TABLE
933+
handler t1 read next;
934+
handler t1 open;
935+
--echo #
936+
--echo # CREATE TRIGGER under LOCK TABLES.
937+
--echo #
938+
lock tables t1 write;
939+
create trigger t1_ai after insert on t1 for each row set @a=1;
940+
unlock tables;
941+
--error ER_UNKNOWN_TABLE
942+
handler t1 read next;
943+
--echo #
944+
--echo # DROP TRIGGER under LOCK TABLES.
945+
--echo #
946+
handler t1 open;
947+
lock tables t1 write;
948+
drop trigger t1_ai;
949+
unlock tables;
950+
--error ER_UNKNOWN_TABLE
951+
handler t1 read next;
952+
--echo #
953+
--echo # ALTER TABLE under LOCK TABLES.
954+
--echo #
955+
handler t1 open;
956+
lock tables t1 write;
957+
alter table t1 drop column b;
958+
unlock tables;
959+
--error ER_UNKNOWN_TABLE
960+
handler t1 read next;
961+
--echo #
962+
--echo # ANALYZE TABLE under LOCK TABLES.
963+
--echo #
964+
handler t1 open;
965+
lock tables t1 write;
966+
analyze table t1;
967+
unlock tables;
968+
--error ER_UNKNOWN_TABLE
969+
handler t1 read next;
970+
--echo #
971+
--echo # OPTIMIZE TABLE under LOCK TABLES.
972+
--echo #
973+
handler t1 open;
974+
lock tables t1 write;
975+
optimize table t1;
976+
unlock tables;
977+
--error ER_UNKNOWN_TABLE
978+
handler t1 read next;
979+
--echo #
980+
--echo # REPAIR TABLE under LOCK TABLES.
981+
--echo #
982+
handler t1 open;
983+
lock tables t1 write;
984+
repair table t1;
985+
unlock tables;
986+
--error ER_UNKNOWN_TABLE
987+
handler t1 read next;
988+
--echo #
989+
--echo # DROP TABLE under LOCK TABLES, naturally.
990+
--echo #
991+
handler t1 open;
992+
lock tables t1 write;
993+
drop table t1;
994+
unlock tables;
995+
--error ER_UNKNOWN_TABLE
996+
handler t1 read next;
997+
create table t1 (a int, b int, key a (a));
998+
insert into t1 (a) values (1), (2), (3), (4), (5);
999+
--echo #
1000+
--echo # FLUSH TABLE doesn't close the table but loses the position
1001+
--echo #
1002+
handler t1 open;
1003+
handler t1 read a prev;
1004+
lock tables t1 write;
1005+
flush table t1;
1006+
unlock tables;
1007+
handler t1 read a prev;
1008+
handler t1 close;
1009+
--echo #
9251010
--echo # Explore the effect of HANDLER locks on concurrent DDL
9261011
--echo #
9271012
handler t1 open;
@@ -1433,6 +1518,8 @@ lock table not_exists_write read;
14331518
--echo # We still have the read lock.
14341519
--error ER_CANT_UPDATE_WITH_READLOCK
14351520
drop table t1;
1521+
handler t1 read next;
1522+
handler t1 close;
14361523
handler t1 open;
14371524
select a from t2;
14381525
handler t1 read next;
@@ -1542,3 +1629,55 @@ SELECT table_name, table_comment FROM information_schema.tables
15421629

15431630
HANDLER t1 CLOSE;
15441631
DROP TABLE t1;
1632+
1633+
1634+
--echo #
1635+
--echo # Test for bug #50908 "Assertion `handler_tables_hash.records == 0'
1636+
--echo # failed in enter_locked_tables_mode".
1637+
--echo #
1638+
--disable_warnings
1639+
drop tables if exists t1, t2;
1640+
drop function if exists f1;
1641+
--enable_warnings
1642+
create table t1 (i int);
1643+
insert into t1 values (1), (2);
1644+
create table t2 (j int);
1645+
insert into t2 values (1);
1646+
create function f1() returns int return (select count(*) from t2);
1647+
--echo # Check that open HANDLER survives statement executed in
1648+
--echo # prelocked mode.
1649+
handler t1 open;
1650+
handler t1 read next;
1651+
--echo # The below statement were aborted due to an assertion failure.
1652+
select f1() from t2;
1653+
handler t1 read next;
1654+
handler t1 close;
1655+
--echo # Check that the same happens under GLOBAL READ LOCK.
1656+
flush tables with read lock;
1657+
handler t1 open;
1658+
handler t1 read next;
1659+
select f1() from t2;
1660+
handler t1 read next;
1661+
unlock tables;
1662+
handler t1 close;
1663+
--echo # Now, check that the same happens if LOCK TABLES is executed.
1664+
handler t1 open;
1665+
handler t1 read next;
1666+
lock table t2 read;
1667+
select * from t2;
1668+
unlock tables;
1669+
handler t1 read next;
1670+
handler t1 close;
1671+
--echo # Finally, check scenario with GRL and LOCK TABLES.
1672+
flush tables with read lock;
1673+
handler t1 open;
1674+
handler t1 read next;
1675+
lock table t2 read;
1676+
select * from t2;
1677+
--echo # This unlocks both tables and GRL.
1678+
unlock tables;
1679+
handler t1 read next;
1680+
handler t1 close;
1681+
--echo # Clean-up.
1682+
drop function f1;
1683+
drop tables t1, t2;

0 commit comments

Comments
 (0)