[MDEV-28980] InnoDB: Failing assertion: len <= MAX_TABLE_NAME_LEN Created: 2022-06-29  Updated: 2022-08-05  Resolved: 2022-07-25

Status: Closed
Project: MariaDB Server
Component/s: Storage Engine - InnoDB
Affects Version/s: 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9
Fix Version/s: 10.3.36, 10.4.26, 10.5.17, 10.6.9, 10.7.5, 10.8.4, 10.9.2, 10.10.1

Type: Bug Priority: Critical
Reporter: Aleksey Midenkov Assignee: Marko Mäkelä
Resolution: Fixed Votes: 0
Labels: None

Issue Links:
Blocks
blocks MDEV-28933 CREATE OR REPLACE fails to recreate s... Closed
Relates
relates to MDEV-29258 Failing assertion for name length on ... Closed

 Description   

Reproduce

--source include/have_innodb.inc
 
set names utf8;
let $d= `select repeat('❎', 45)`;
let $t= `select repeat('❎', 64)`;
eval create database `$d`;
eval use `$d`;
create table t (a int primary key) engine=innodb;
eval create or replace table u (
  a int primary key,
  constraint `$t` foreign key d (a) references t (a)) engine=innodb;
#select * from information_schema.innodb_sys_foreign;
eval create or replace table u (
  a int primary key,
  constraint `$t` foreign key d (a) references t (a)) engine=innodb;
#select * from information_schema.innodb_sys_foreign;
show create table u;
use test;
eval drop database `$d`;

Result

0ba528fe56f

#5  0x00005580cf377991 in ut_dbg_assertion_failed (expr=0x5580cf8d2fec "len <= MAX_TABLE_NAME_LEN", file=0x5580cf95086b "../src/storage/innobase/dict/dict0load.cc", line=3690) at ../src/storage/innobase/ut/ut0dbg.cc:60
#6  0x00005580cf44f98e in dict_load_foreigns (table_name=0x7f43c80ee490 "@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e/u", col_names=0x0, check_recursive=false, check_charsets=true, ignore_err=DICT_ERR_IGNORE_NONE, fk_tables=std::deque with 0 elements) at ../src/storage/innobase/dict/dict0load.cc:3690
#7  0x00005580cf133244 in create_table_info_t::create_table (this=0x7f43c80ee208, create_fk=true) at ../src/storage/innobase/handler/ha_innodb.cc:12718
#8  0x00005580cf14f4ad in ha_innobase::create (this=0x7f43d002a9c0, name=0x7f43c80f1b20 "./@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e/u", form=0x7f43c80eef08, create_info=0x7f43c80f2080, file_per_table=true, trx=0x7f43e02dc218) at ../src/storage/innobase/handler/ha_innodb.cc:13167
#9  0x00005580cf134157 in ha_innobase::create (this=0x7f43d002a9c0, name=0x7f43c80f1b20 "./@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e/u", form=0x7f43c80eef08, create_info=0x7f43c80f2080) at ../src/storage/innobase/handler/ha_innodb.cc:13220
#10 0x00005580ceef71c3 in handler::ha_create (this=0x7f43d002a9c0, name=0x7f43c80f1b20 "./@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e/u", form=0x7f43c80eef08, info_arg=0x7f43c80f2080) at ../src/sql/handler.cc:4510
#11 0x00005580ceef8394 in ha_create_table (thd=0x7f43d0008ef8, path=0x7f43c80f1b20 "./@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e/u", db=0x7f43d001c3b8 "❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎", table_name=0x7f43d001bd48 "u", create_info=0x7f43c80f2080, frm=0x7f43c80f1b10) at ../src/sql/handler.cc:4883
#12 0x00005580ced98188 in rea_create_table (thd=0x7f43d0008ef8, frm=0x7f43c80f1b10, path=0x7f43c80f1b20 "./@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e/u", db=0x7f43d001c3b8 "❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎", table_name=0x7f43d001bd48 "u", create_info=0x7f43c80f2080, file=0x7f43d001ce80, no_ha_create_table=false) at ../src/sql/unireg.cc:429
#13 0x00005580ced366f8 in create_table_impl (thd=0x7f43d0008ef8, orig_db=0x7f43d001c3b8 "❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎", orig_table_name=0x7f43d001bd48 "u", db=0x7f43d001c3b8 "❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎", table_name=0x7f43d001bd48 "u", path=0x7f43c80f1b20 "./@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e@274e/u", options=..., create_info=0x7f43c80f2080, alter_info=0x7f43c80f1fd8, create_table_mode=0, is_trans=0x7f43c80f1e47, key_info=0x7f43c80f1d38, key_count=0x7f43c80f1d34, frm=0x7f43c80f1b10) at ../src/sql/sql_table.cc:5006
#14 0x00005580ced35be6 in mysql_create_table_no_lock (thd=0x7f43d0008ef8, db=0x7f43d001c3b8 "❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎", table_name=0x7f43d001bd48 "u", create_info=0x7f43c80f2080, alter_info=0x7f43c80f1fd8, is_trans=0x7f43c80f1e47, create_table_mode=0) at ../src/sql/sql_table.cc:5116
#15 0x00005580ced36e2c in mysql_create_table (thd=0x7f43d0008ef8, create_table=0x7f43d001bd98, create_info=0x7f43c80f2080, alter_info=0x7f43c80f1fd8) at ../src/sql/sql_table.cc:5184
#16 0x00005580ced4897a in Sql_cmd_create_table::execute (this=0x7f43d001bd78, thd=0x7f43d0008ef8) at ../src/sql/sql_table.cc:11067
#17 0x00005580cec5e6bd in mysql_execute_command (thd=0x7f43d0008ef8) at ../src/sql/sql_parse.cc:6017
#18 0x00005580cec52928 in mysql_parse (thd=0x7f43d0008ef8, rawbuf=0x7f43d001ba00 "create or replace table u (\na int primary key,\nconstraint `❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎ ❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎❎` foreign key d (a) references t (a)) engine=innodb", length=302, parser_state=0x7f43c80f4560, is_com_multi=false, is_next_command=false) at ../src/sql/sql_parse.cc:7793

3682            /* Now we get a foreign key constraint id */
3683            field = rec_get_nth_field_old(
3684                    rec, DICT_FLD__SYS_FOREIGN_FOR_NAME__ID, &len);
3685
3686            /* Copy the string because the page may be modified or evicted
3687            after mtr_commit() below. */
3688            char    fk_id[MAX_TABLE_NAME_LEN + 1];
3689
3690            ut_a(len <= MAX_TABLE_NAME_LEN);



 Comments   
Comment by Marko Mäkelä [ 2022-07-25 ]

I reproduced this with a simpler test case, using a minimal-length database name (26*5 characters in my_charset_filename), and with 64 normal-width 3-byte UTF-8 glyphs in the constraint name:

--source include/have_innodb.inc
set names utf8;
create table t (a int primary key) engine=innodb;
let $d=##########################;
eval create database `$d`;
eval create table `$d`.u (
  a int primary key,
  constraint `††††††††††††††††††††††††††††††††††††††††††††††††††††††††††††††††`
  foreign key (a) references test.t (a)) engine=innodb;
eval drop database `$d`;
drop table t;

10.3 95989e82114f74b4c8b6bb47456794811f0c3f8b

2022-07-25 08:24:09 0x7fa4fd7de640  InnoDB: Assertion failure in file /mariadb/10.3/storage/innobase/dict/dict0load.cc line 3656
InnoDB: Failing assertion: len <= MAX_TABLE_NAME_LEN

The SYS_FOREIGN.ID will contain the database name in the filename-safe encoding, a separator /, and the constraint name. This easily exceeds the MAX_TABLE_NAME_LEN (5*64=320). The actual maximum length of SYS_FOREIGN.ID should be 5*64+1+3*64=513 bytes, but operating systems may restrict the path component length further. In Linux, a path component may be up to 255 bytes. So, the maximum database name length would be 51 characters when each of them is encoded in 5 bytes.

The internal SQL interpreter of InnoDB does not really enforce any maximum length; we saw it in MDEV-14637 already, where an exception was implemented for SYS_FOREIGN and SYS_FOREIGN_COLS. As far as I can tell, the maximum record length would be achieved for the SYS_FOREIGN secondary indexes (FOR_NAME,ID) and (REF_NAME,ID): 5*64+1+5*64 = 641 bytes for the table name and 513 bytes for the FOREIGN KEY identifier. Those 1154 bytes are nowhere near the maximum record length, which is almost twice as long even with the minimal innodb_page_size=4k.

The SYS_FOREIGN.ID could be potentially longer for implicitly created constraint names. In that case, the string _ibfk_ and a number (presumably up to 2 or 3 digits) would be appended to the table name. However, in such a case the FN_REFLEN (512 bytes) would kick in way before the maximum-length database and table name (641 bytes) are exceeded. Even with 255-byte table and database names (51*5 characters), the limit will be exceeded, because the total length would be 2+255+1+255 = 513 bytes. The actual maximum length that I got to work is a 255-byte database name and a 250-byte table name.

Generated at Thu Feb 08 10:04:57 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.