Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-28980

InnoDB: Failing assertion: len <= MAX_TABLE_NAME_LEN

Details

    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);
      

      Attachments

        Issue Links

          Activity

            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.

            marko Marko Mäkelä added a comment - 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.

            People

              marko Marko Mäkelä
              midenok Aleksey Midenkov
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.