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

PARTITION BY KEY and UNIQUE USING HASH treat equal CHAR values in a NO PAD collation as different: duplicate keys and missing rows

    XMLWordPrintable

Details

    Description

      --source include/have_partition.inc
      --source include/have_innodb.inc
       
      SET NAMES utf8mb4;
       
      # 'a', 'ä' and 'a' are equal in utf8mb4_unicode_nopad_ci
      CREATE TABLE t1 (a CHAR(10) COLLATE utf8mb4_unicode_nopad_ci, PRIMARY KEY (a)) ENGINE=InnoDB PARTITION BY KEY (a) PARTITIONS 8;
      INSERT IGNORE INTO t1 VALUES ('a'),('ä'),('a');
      --let $c= query_get_value(SELECT COUNT(*) AS c FROM t1, c, 1)
      if ($c != 1)
      {
        --die The PRIMARY KEY holds $c values that are equal in utf8mb4_unicode_nopad_ci, where it must hold one
      }
       
      CREATE TABLE t2 (a CHAR(10) COLLATE utf8mb4_unicode_nopad_ci) PARTITION BY KEY (a) PARTITIONS 8;
      INSERT INTO t2 VALUES ('a'),('ä'),('a');
      --let $c= query_get_value(SELECT COUNT(*) AS c FROM t2 WHERE a='ä', c, 1)
      if ($c != 3)
      {
        --die The condition a='ä' finds $c of the 3 rows that are equal to 'ä' in utf8mb4_unicode_nopad_ci
      }
       
      CREATE TABLE t3 (a CHAR(10) COLLATE utf8mb4_unicode_nopad_ci, UNIQUE (a) USING HASH);
      INSERT IGNORE INTO t3 VALUES ('a'),('ä'),('a');
      --let $c= query_get_value(SELECT COUNT(*) AS c FROM t3, c, 1)
      if ($c != 1)
      {
        --die The UNIQUE USING HASH column holds $c values that are equal in utf8mb4_unicode_nopad_ci, where it must hold one
      }
      DROP TABLE t1, t2, t3;

      Leads to:

      CS 13.1.0 da18481158c81ca94689702073c3e04aad85a6a3 (Debug, Clang 22.1.8-20260622) Build 18/08/2026

      mysqltest: At line 12: The PRIMARY KEY holds 3 values that are equal in utf8mb4_unicode_nopad_ci, where it must hold one

      The PRIMARY KEY of t1 and the UNIQUE ... USING HASH of t3 accept three equal values. On t2, partitioning changes the query result. The t2 and t3 parts fail in the same way when run on their own. t3 has no partitioning. With VARCHAR, or with the PAD SPACE collation utf8mb4_unicode_ci, t1 and t3 hold one row. Optimized builds give the same result.

      From the code it seems that CHAR uses Field::hash_not_null() in sql/field.cc, which hashes all pack_length() bytes, the space padding included. 'a', 'ä' and 'a' take 1, 2 and 3 bytes, so each one is stored with a different number of padding spaces. The NO PAD hash function does not skip trailing spaces, so the three equal values get three different hashes. PARTITION BY KEY and UNIQUE ... USING HASH both use this hash. Field_varstring::hash_not_null() hashes only the value itself.

      Attachments

        Issue Links

          Activity

            People

              raghunandan.bhat Raghunandan Bhat
              Roel Roel Van de Paar
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:

                Time Tracking

                  Estimated:
                  Original Estimate - 0d
                  0d
                  Remaining:
                  Time Spent - 1.25h Remaining Estimate - 1.5d
                  1.5d
                  Logged:
                  Time Spent - 1.25h Remaining Estimate - 1.5d
                  1.25h

                  Git Integration

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