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

strnncollsp_nchars() gets called in a suspicious way from InnoDB

    XMLWordPrintable

Details

    Description

      I apply this patch:

      --- a/storage/innobase/rem/rem0cmp.cc
      +++ b/storage/innobase/rem/rem0cmp.cc
      @@ -326,8 +326,11 @@ static int cmp_whole_field(ulint mtype, ulint prtype,
           DBUG_ASSERT(is_strnncoll_compatible(prtype & DATA_MYSQL_TYPE_MASK));
           if (CHARSET_INFO *cs= get_charset(dtype_get_charset_coll(prtype),
                                             MYF(MY_WME)))
      +    {
      +      DBUG_ASSERT(a_length == b_length || cs->mbminlen != cs->mbmaxlen);
             return cs->coll->strnncollsp_nchars(cs, a, a_length, b, b_length,
                                                 std::max(a_length, b_length));
      +    }
         }
      

      The idea of the assert is to prove that InnoDB for the CHAR(N) data type:

      • performs trailing space compression for variable length encodings (e.g. utf8)
      • does not perform trailing space compression for fixed length encodings (e.g. latin1)

      Then I run this script:

      drop table if exists t2,t1;
      create table t1 (a int primary key,s1 varchar(2) character set latin1 collate latin1_bin not null unique) engine=innodb;
      create table t2 (s1 char(2) character set latin1 collate latin1_bin not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb;
      insert into t1 values(1,0x4100),(2,0x41);
      insert into t2 values(0x41);
      

      the server crashes on the new assert when doing the insert into t2.

      Tracing in gdb show that the lengths are different indeed:

      (gdb) p	a_length
      $1 = 2
      (gdb) p	b_length
      $2 = 1
      

      If I change the collation from latin1_bin to latin1_german1_ci:

      drop table if exists t2,t1;
      create table t1 (a int primary key,s1 varchar(2) character set latin1 collate latin1_german1_ci not null unique) engine=innodb;
      create table t2 (s1 char(2) character set latin1 collate latin1_german1_ci not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb;
      insert into t1 values(1,0x4100),(2,0x41);
      insert into t2 values(0x41);
      

      it does not crash.

      Tracing the same place shows that lengths are equal:

      (gdb) p	a_length
      $3 = 2
      (gdb) p	b_length
      $4 = 2
      

      This looks suspicious. The two collations should work symmetrically in this context.

      • latin1_bin behaviour does not seem to be expected
      • latin1_german1_ci seems to work fine

      Attachments

        Activity

          People

            marko Marko Mäkelä
            bar Alexander Barkov
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:

              Git Integration

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