|
In MDEV-13564, we changed ha_innobase::truncate() to internally perform RENAME, CREATE and DROP.
The LOCK TABLE is apparently interfering with the following DDL statements. As far as I can tell, the statement
ALTER TABLE t1 ADD c INT;
|
completed just fine inside InnoDB (in 10.2, or without the MDEV-20590 SET GLOBAL innodb_instant_alter_column_allowed=never, it will rebuild the table).
The immediate cause for the failure appears to be that HA_ERR_NO_SUCH_TABLE is being returned by ha_innobase::open() upon the completion of the operation:
|
10.2 5ecaf52d42a1e464c71515f35be97855072bcafe
|
#0 0x0000564145903824 in handler::ha_open (this=0x7ffae4037420, table_arg=0x7ffae4042128, name=0x7ffae4023190 "./test/t1", mode=2, test_if_locked=18) at /mariadb/10.2o/sql/handler.cc:2592
|
#1 0x00005641457fc6ab in open_table_from_share (thd=thd@entry=0x7ffae4008f48, share=<optimized out>, share@entry=0x7ffae4022c80, alias=<optimized out>, db_stat=<optimized out>, db_stat@entry=33,
|
prgflag=<optimized out>, prgflag@entry=8, ha_open_flags=<optimized out>, outparam=<optimized out>, is_create_table=<optimized out>) at /mariadb/10.2o/sql/table.cc:3422
|
#2 0x00005641456ed720 in open_table (thd=thd@entry=0x7ffae4008f48, table_list=table_list@entry=0x7ffae401bc88, ot_ctx=ot_ctx@entry=0x7ffae80f24b0) at /mariadb/10.2o/sql/sql_base.cc:1934
|
#3 0x00005641457db599 in mysql_inplace_alter_table (thd=0x7ffae4008f48, table_list=0x7ffae401bc88, table=0x0, altered_table=0x7ffae404a258, ha_alter_info=0x7ffae80f27d0,
|
inplace_supported=HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE, target_mdl_request=<optimized out>, alter_ctx=0x7ffae80f1a00) at /mariadb/10.2o/sql/sql_table.cc:7522
|
#4 mysql_alter_table (thd=<optimized out>, thd@entry=0x7ffae4008f48, new_db=<optimized out>, new_name=<optimized out>, create_info=<optimized out>, create_info@entry=0x7ffae80f2e68,
|
table_list=table_list@entry=0x7ffae401bc88, alter_info=<optimized out>, alter_info@entry=0x7ffae80f35b8, order_num=<optimized out>, order=<optimized out>, ignore=<optimized out>)
|
at /mariadb/10.2o/sql/sql_table.cc:9627
|
#5 0x000056414582ea72 in Sql_cmd_alter_table::execute (this=<optimized out>, thd=0x7ffae4008f48) at /mariadb/10.2o/sql/sql_alter.cc:333
|
#6 0x000056414573f575 in mysql_execute_command (thd=<optimized out>, thd@entry=0x7ffae4008f48) at /mariadb/10.2o/sql/sql_parse.cc:5994
|
#7 0x000056414573cd27 in mysql_parse (thd=thd@entry=0x7ffae4008f48, rawbuf=0x7ffae401bbb0 "ALTER TABLE t1 ADD c INT", length=<optimized out>, parser_state=parser_state@entry=0x7ffae80f46f0,
|
is_com_multi=false, is_next_command=false) at /mariadb/10.2o/sql/sql_parse.cc:7763
|
The reason for this appears to be that ha_innobase::open() is being invoked with the wrong TABLE_SHARE (corresponding to the old table definition, before the ADD COLUMN):
if (UNIV_UNLIKELY(n_cols != n_fields)) {
|
ib::warn() << "Table " << norm_name << " contains "
|
<< n_cols << " user"
|
" defined columns in InnoDB, but " << n_fields
|
<< " columns in MariaDB. Please check"
|
" INFORMATION_SCHEMA.INNODB_SYS_COLUMNS and"
|
" https://mariadb.com/kb/en/innodb-data-dictionary-troubleshooting/"
|
" for how to resolve the issue.";
|
|
/* Mark this table as corrupted, so the drop table
|
or force recovery can still use it, but not others. */
|
ib_table->file_unreadable = true;
|
ib_table->corrupted = true;
|
dict_table_close(ib_table, FALSE, FALSE);
|
goto no_such_table;
|
}
|
I suspect that this bug could occur independent of the MDEV-13564 change, in the highly unlikely case that the table definition had been evicted from the InnoDB data dictionary cache during this.
I hope that monty can shed some light on this. He recently helped fix MDEV-24564, which is a little similar.
|
|
I put a breakpoint on mysql_rename_table, just before the open_table code.
I noticed that, probably because of truncate, we had two ibd files
t1.ibd
#sql-5306_9
I put a breakpoint on the above code and got the error:
nnoDB: Table test/t1 contains 2 user defined columns in InnoDB, but 3 columns in MariaDB.
Why is InnoDB still using the old version of the table with 2 fields, when it should be 3 fields after the alter_table_inplace and as ha_commit_inplace_alter_table() has already been called.
One possible solution is that InnoDB did all the alter table changes in the old #sql- table (left from truncate).
|
|
Sorry, I got the reason for the mismatch the wrong way around. The problem ought to be caused by MDEV-13564, which is internally executing RENAME, CREATE, and DROP. For some reason (possibly due to the LOCK TABLE), we are getting the wrong table passed to ALTER TABLE:
|
10.3 25ecf8ed4b4cbca69a9fa09c27bbd4e5c83fafe3
|
(rr) p m_prebuilt->table->name
|
$6 = {m_name = 0x7f729403a4a0 "test/#sql-ib21"}
|
(rr) bt
|
#0 ha_innobase::check_if_supported_inplace_alter (this=0x7f72940552e0,
|
altered_table=0x7f729405bf18, ha_alter_info=0x7f72ac04c290)
|
at /mariadb/10.3/storage/innobase/handler/handler0alter.cc:950
|
#1 0x0000562bbdfc1357 in mysql_alter_table (thd=thd@entry=0x7f7294017048,
|
new_db=new_db@entry=0x7f729401b730,
|
new_name=new_name@entry=0x7f729401baf8,
|
create_info=create_info@entry=0x7f72ac04d6b0, table_list=<optimized out>,
|
table_list@entry=0x7f7294022c98,
|
alter_info=alter_info@entry=0x7f72ac04d5f0, order_num=0, order=0x0,
|
ignore=false) at /mariadb/10.3/sql/sql_table.cc:9955
|
#2 0x0000562bbe02a529 in Sql_cmd_alter_table::execute (this=<optimized out>,
|
thd=0x7f7294017048) at /mariadb/10.3/sql/sql_alter.cc:512
|
#3 0x0000562bbdf0c848 in mysql_execute_command (thd=thd@entry=0x7f7294017048)
|
at /mariadb/10.3/sql/sql_parse.cc:6053
|
#4 0x0000562bbdf0e072 in mysql_parse (thd=thd@entry=0x7f7294017048,
|
rawbuf=<optimized out>, length=<optimized out>,
|
parser_state=parser_state@entry=0x7f72ac04e570,
|
is_com_multi=is_com_multi@entry=false,
|
is_next_command=is_next_command@entry=false)
|
at /mariadb/10.3/sql/sql_parse.cc:7841
|
#5 0x0000562bbdf107d5 in dispatch_command (command=command@entry=COM_QUERY,
|
thd=thd@entry=0x7f7294017048, packet=0x7f72ac04e570 "\377\377\377\377",
|
packet@entry=0x7f7294009f59 "ALTER TABLE t1 ADD c INT",
|
This is the old table that was supposed to be discarded by TRUNCATE TABLE t1.
|
|
When doing a truncate on an Innodb under lock tables, InnoDB would rename the old table to #sql-... and recreate a new 't1' table. The table lock would still be on the #sql-table.
When doing ALTER TABLE, Innodb would do the changes on the #sql table (which would disappear on close).
When the SQL layer, as part of inline alter table, would close the original t1 table (#sql in InnoDB) and then reopen the t1 table, Innodb would notice that this does not match it's own (old) t1 table and generate an error.
Fixed by adding code in truncate table that if we are under lock tables and truncating an InnoDB table, we would close and reopen and lock the table after truncate. This will remove the #sql table and ensure that lock tables is using the new empty table.
|