Description:
Look at the following code.
bool Sql_cmd_alter_table_exchange_partition::
exchange_partition(THD *thd, TABLE_LIST *table_list, Alter_info *alter_info)
{
...
int ha_error= part_handler->exchange_partition(part_file_name,
swap_file_name,
swap_part_id,
part_table_def,
swap_table_def);
if (ha_error)
{
part_table->file->print_error(ha_error, MYF(0));
// Close TABLE instances which marked as old earlier.
close_all_tables_for_name(thd, swap_table->s, false, NULL);
close_all_tables_for_name(thd, part_table->s, false, NULL);
...
if ((part_table->file->ht->flags & HTON_SUPPORTS_ATOMIC_DDL) &&
part_table->file->ht->post_ddl)
part_table->file->ht->post_ddl(thd);
(void) thd->locked_tables_list.reopen_tables(thd);
DBUG_RETURN(true);
}
...
}
If handler::exchange_partition(...) returns error then close_all_tables_for_name(...) is invoked, what, in turns, leads to
part_table->file zeroing out. See the following backtrace:
(gdb)
closefrm (table=0x7fff542c13f0, free_share=true) at ./sql/table.cc:3470
3470 table->file= 0; /* For easier errorchecking */
(gdb) bt
#0 closefrm (table=0x7fff542c13f0, free_share=true) at ./sql/table.cc:3470
#1 0x0000000002a3dae6 in intern_close_table (table=0x7fff542c13f0) at ./sql/sql_base.cc:1165
#2 0x0000000002a3ee46 in release_or_close_table (thd=0x7fff5435d990, table=0x7fff542c13f0) at ./sql/sql_base.cc:1858
#3 0x0000000002a3f0a3 in close_thread_table (thd=0x7fff5435d990, table_ptr=0x7fff5435d9f8) at ./sql/sql_base.cc:1904
#4 0x0000000002a3e698 in close_all_tables_for_name (thd=0x7fff5435d990, key=0x7fffe7efc520 "test", key_length=8, db=0x7fffe7efc520 "test",
table_name=0x7fffe7efc525 "t1", remove_from_locked_tables=false, skip_table=0x0) at ./sql/sql_base.cc:1557
#5 0x0000000002a3e79c in close_all_tables_for_name (thd=0x7fff5435d990, share=0x7fff543b3fa0, remove_from_locked_tables=false, skip_table=0x0)
at ./sql/sql_base.cc:1588
#6 0x0000000003234d9b in Sql_cmd_alter_table_exchange_partition::exchange_partition (this=0x7fff540ea230, thd=0x7fff5435d990, table_list=0x7fff540e96d8,
alter_info=0x7fffe7efe130) at ./sql/sql_partition_admin.cc:512
#7 0x00000000032337d4 in Sql_cmd_alter_table_exchange_partition::execute (this=0x7fff540ea230, thd=0x7fff5435d990)
at ./sql/sql_partition_admin.cc:113
#8 0x0000000002ae5ee6 in mysql_execute_command (thd=0x7fff5435d990, first_level=true) at ./sql/sql_parse.cc:4645
#9 0x0000000002ae84ea in mysql_parse (thd=0x7fff5435d990, parser_state=0x7fffe7eff390) at ./sql/sql_parse.cc:5441
#10 0x0000000002adde8c in dispatch_command (thd=0x7fff5435d990, com_data=0x7fffe7effcf0, command=COM_QUERY)
at ./sql/sql_parse.cc:1730
#11 0x0000000002adc850 in do_command (thd=0x7fff5435d990) at ./sql/sql_parse.cc:1310
#12 0x0000000002e64ea7 in handle_connection (arg=0x8c6be90) at ./sql/conn_handler/connection_handler_per_thread.cc:335
#13 0x000000000434794e in pfs_spawn_thread (arg=0x8cb4ca0) at ./storage/perfschema/pfs.cc:2994
#14 0x00007ffff79be6ba in start_thread (arg=0x7fffe7f00700) at pthread_create.c:333
#15 0x00007ffff5d7341d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
After that null pointer is dereferenced in the following code:
if ((part_table->file->ht->flags & HTON_SUPPORTS_ATOMIC_DDL) &&
part_table->file->ht->post_ddl)
part_table->file->ht->post_ddl(thd);
How to repeat:
The short way is just code review. The more complex way - create storage engine which does not implement handler::exchange_partition_low(...) method.
Suggested fix:
Invoke close_all_tables_for_name() after part_table->file dereferencing.