Bug #73601 Crash on direct insert into mysql.gtid_executed table
Submitted: 15 Aug 2014 12:33 Modified: 26 Mar 2015 8:48
Reporter: Sven Sandberg Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Replication Severity:S2 (Serious)
Version:5.7 OS:Any
Assigned to: CPU Architecture:Any

[15 Aug 2014 12:33] Sven Sandberg
Description:
When gtid_mode=on and binary log is off, the server automatically inserts the transaction's GTID into mysql.gtid_executed within the transaction.

But if the GTID has already been inserted into the table by an explicit INSERT statement, the server crashes.

Explicit insert into mysql.gtid_executed is a strange and unsupported operation, but of course the server should not crash.

How to repeat:
==== .opt file ====
--skip-log-bin --gtid-mode=on --enforce-gtid-consistency

==== Test 1: GTID inserted before transaction ====
# Use the .opt file above.
--let $uuida=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa
eval INSERT INTO mysql.gtid_executed VALUES ('$uuida', 1, 1);

eval SET GTID_NEXT = '$uuida:1';
CREATE TABLE t1 (a INT);

==== Test 2: GTID inserted within transaction ====
# Use the .opt file above.
--let $uuida=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa
eval SET GTID_NEXT = '$uuida:1';
eval INSERT INTO mysql.gtid_executed VALUES ('$uuida', 1, 1);

==== Test 3: GTID inserted by concurrent transaction ====
# Use the .opt file above.
--connect (con2,127.0.0.1,root,,test,$MASTER_MYPORT,)

--let $uuida=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa
eval SET GTID_NEXT = '$uuida:1';

--connection con2
eval INSERT INTO mysql.gtid_executed VALUES ('$uuida', 1, 1);

--connection default
CREATE TABLE t1 (a INT);

==== Stack trace ====
Thread 1 (Thread 0x7fbd046bb700 (LWP 27396)):
#0  0x00007fbd0c2d8f0c in pthread_kill () from /lib/x86_64-linux-gnu/libpthread.so.0
#1  0x0000000000e0ac91 in my_write_core (sig=6) at /home/sven/bzr/debug/trunk/mysys/stacktrace.c:246
#2  0x000000000081f494 in handle_fatal_signal (sig=6) at /home/sven/bzr/debug/trunk/sql/signal_handler.cc:219
#3  <signal handler called>
#4  0x00007fbd0b71cf77 in raise () from /lib/x86_64-linux-gnu/libc.so.6
#5  0x00007fbd0b7205e8 in abort () from /lib/x86_64-linux-gnu/libc.so.6
#6  0x00007fbd0b715d43 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#7  0x00007fbd0b715df2 in __assert_fail () from /lib/x86_64-linux-gnu/libc.so.6
#8  0x000000000088dfed in Ha_trx_info::is_trx_read_write (this=0x7fbcc00134b0) at /home/sven/bzr/debug/trunk/sql/transaction_info.h:108
#9  0x000000000087e126 in ha_check_and_coalesce_trx_read_only (thd=0x7fbcc0011f70, ha_list=0x7fbcc00134b0, all=false) at /home/sven/bzr/debug/trunk/sql/handler.cc:1332
#10 0x000000000087e4de in ha_commit_trans (thd=0x7fbcc0011f70, all=false, ignore_global_read_lock=false) at /home/sven/bzr/debug/trunk/sql/handler.cc:1466
#11 0x0000000000c10f87 in trans_commit_stmt (thd=0x7fbcc0011f70) at /home/sven/bzr/debug/trunk/sql/transaction.cc:367
#12 0x0000000000b32ffe in mysql_execute_command (thd=0x7fbcc0011f70) at /home/sven/bzr/debug/trunk/sql/sql_parse.cc:4857
#13 0x0000000000b347d1 in mysql_parse (thd=0x7fbcc0011f70, parser_state=0x7fbd046b9e80) at /home/sven/bzr/debug/trunk/sql/sql_parse.cc:5398
#14 0x0000000000b28e2b in dispatch_command (command=COM_QUERY, thd=0x7fbcc0011f70, packet=0x7fbcc0007761 "INSERT INTO mysql.gtid_executed VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-", 'a' <repeats 12 times>, "', 1, 1)", packet_length=85) at /home/sven/bzr/debug/trunk/sql/sql_parse.cc:1247
#15 0x0000000000b27b7f in do_command (thd=0x7fbcc0011f70) at /home/sven/bzr/debug/trunk/sql/sql_parse.cc:834
#16 0x0000000000c39ce6 in handle_connection (arg=0x29da170) at /home/sven/bzr/debug/trunk/sql/conn_handler/connection_handler_per_thread.cc:298
#17 0x0000000001131d2b in pfs_spawn_thread (arg=0x29cedc0) at /home/sven/bzr/debug/trunk/storage/perfschema/pfs.cc:2072
#18 0x00007fbd0c2d3f6e in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
#19 0x00007fbd0b7e09cd in clone () from /lib/x86_64-linux-gnu/libc.so.6

Suggested fix:
This is a very strange thing for the user to do. It probably happens
because the automatic insertion of the GTID into the table does not
expect the duplicate key error.

Suggested fix:

- Make the code that automatically inserts a GTID into the table skip
  the insert in case of a duplicate key error.

- Generate a warning whenever user manually inserts into the table.
[26 Mar 2015 8:48] David Moss
The following was added to the 5.7.8 changelog:
 
When gtid_mode=on, GTIDs are automatically added to the mysql.gtid_executed table. If a GTID was manually inserted into the mysql.gtid_executed table and then automatic update inserted the same GTID, the server crashed. Manually inserting GTIDs into mysql.gtid_executed is an unsupported operation, but this fix ensures that the server does not crash in such a situation.