summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/innodb/r/instant_alter_charset.result33
-rw-r--r--mysql-test/suite/innodb/t/instant_alter_charset.test31
-rw-r--r--storage/innobase/data/data0type.cc4
-rw-r--r--storage/innobase/dict/dict0dict.cc3
-rw-r--r--storage/innobase/dict/dict0load.cc6
-rw-r--r--storage/innobase/handler/ha_innodb.cc2
6 files changed, 76 insertions, 3 deletions
diff --git a/mysql-test/suite/innodb/r/instant_alter_charset.result b/mysql-test/suite/innodb/r/instant_alter_charset.result
index 8b1171191fa..43b4b2453e8 100644
--- a/mysql-test/suite/innodb/r/instant_alter_charset.result
+++ b/mysql-test/suite/innodb/r/instant_alter_charset.result
@@ -2043,3 +2043,36 @@ constraint a foreign key (id) references t1 (id)
alter table t1 change id id2 int;
drop table t2;
drop table t1;
+#
+# MDEV-25951 MariaDB crash after ALTER TABLE convert to utf8mb4
+#
+CREATE TABLE t1 (id INT PRIMARY KEY, a VARCHAR(32), KEY (a(7))) ENGINE=INNODB DEFAULT CHARSET=UTF8;
+INSERT INTO t1 VALUES (1, 'a1'), (2, 'a1');
+ALTER TABLE t1
+CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci,
+ADD UNIQUE INDEX test_key (a);
+ERROR 23000: Duplicate entry 'a1' for key 'test_key'
+ALTER TABLE t1 CONVERT TO CHARACTER SET UTF8MB4 COLLATE UTF8MB4_UNICODE_520_CI;
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+SELECT * FROM t1;
+id a
+1 a1
+2 a1
+DROP TABLE t1;
+CREATE TABLE t1 (id INT PRIMARY KEY, a CHAR(32), KEY (a(7))) ENGINE=INNODB DEFAULT CHARSET=UTF8;
+INSERT INTO t1 VALUES (1, 'a1'), (2, 'a1');
+ALTER TABLE t1
+CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci,
+ADD UNIQUE INDEX test_key (a);
+ERROR 23000: Duplicate entry 'a1' for key 'test_key'
+ALTER TABLE t1 CONVERT TO CHARACTER SET UTF8MB4 COLLATE UTF8MB4_UNICODE_520_CI;
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+SELECT * FROM t1;
+id a
+1 a1
+2 a1
+DROP TABLE t1;
diff --git a/mysql-test/suite/innodb/t/instant_alter_charset.test b/mysql-test/suite/innodb/t/instant_alter_charset.test
index 1d444b88a7f..d64e30402ed 100644
--- a/mysql-test/suite/innodb/t/instant_alter_charset.test
+++ b/mysql-test/suite/innodb/t/instant_alter_charset.test
@@ -857,3 +857,34 @@ create table t2 (input_id int primary key, id int not null,
alter table t1 change id id2 int;
drop table t2;
drop table t1;
+
+
+--echo #
+--echo # MDEV-25951 MariaDB crash after ALTER TABLE convert to utf8mb4
+--echo #
+
+CREATE TABLE t1 (id INT PRIMARY KEY, a VARCHAR(32), KEY (a(7))) ENGINE=INNODB DEFAULT CHARSET=UTF8;
+INSERT INTO t1 VALUES (1, 'a1'), (2, 'a1');
+
+--error ER_DUP_ENTRY
+ALTER TABLE t1
+ CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci,
+ ADD UNIQUE INDEX test_key (a);
+
+ALTER TABLE t1 CONVERT TO CHARACTER SET UTF8MB4 COLLATE UTF8MB4_UNICODE_520_CI;
+CHECK TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (id INT PRIMARY KEY, a CHAR(32), KEY (a(7))) ENGINE=INNODB DEFAULT CHARSET=UTF8;
+INSERT INTO t1 VALUES (1, 'a1'), (2, 'a1');
+
+--error ER_DUP_ENTRY
+ALTER TABLE t1
+ CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci,
+ ADD UNIQUE INDEX test_key (a);
+
+ALTER TABLE t1 CONVERT TO CHARACTER SET UTF8MB4 COLLATE UTF8MB4_UNICODE_520_CI;
+CHECK TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
diff --git a/storage/innobase/data/data0type.cc b/storage/innobase/data/data0type.cc
index 7de4cc026d1..b1952bcc2a4 100644
--- a/storage/innobase/data/data0type.cc
+++ b/storage/innobase/data/data0type.cc
@@ -61,10 +61,10 @@ dtype_get_at_most_n_mbchars(
length is being determined */
{
ut_a(len_is_stored(data_len));
- ut_ad(!mbmaxlen || !(prefix_len % mbmaxlen));
+ ut_ad(!mbmaxlen || !(prefix_len % mbmaxlen) || !(prefix_len % 4));
if (mbminlen != mbmaxlen) {
- ut_a(!(prefix_len % mbmaxlen));
+ ut_a(!(prefix_len % mbmaxlen) || !(prefix_len % 4));
return(innobase_get_at_most_n_mbchars(
dtype_get_charset_coll(prtype),
prefix_len, data_len, str));
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index f22e106b6b8..8357732e73b 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -1916,7 +1916,8 @@ dict_index_add_to_cache(
/* Set the max_prefix value based on the
prefix_len. */
ut_ad(field->col->is_binary()
- || field->prefix_len % field->col->mbmaxlen == 0);
+ || field->prefix_len % field->col->mbmaxlen == 0
+ || field->prefix_len % 4 == 0);
field->col->max_prefix = field->prefix_len;
}
ut_ad(field->col->ord_part == 1);
diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc
index 0c6810dccc3..623403db3c8 100644
--- a/storage/innobase/dict/dict0load.cc
+++ b/storage/innobase/dict/dict0load.cc
@@ -2576,6 +2576,12 @@ corrupted:
!= DB_SUCCESS) {
goto func_exit;
}
+
+ for (uint i = 0; i < index->n_fields; i++) {
+ dict_field_t &f = index->fields[i];
+ ut_ad(f.col->mbmaxlen == 0
+ || f.prefix_len % f.col->mbmaxlen == 0);
+ }
}
next_rec:
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index ac066be7b42..4316a3a4671 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -11351,6 +11351,8 @@ create_index(
prefix_len = 0;
}
+ ut_ad(prefix_len % field->charset()->mbmaxlen == 0);
+
field_lengths[i] = key_part->length;
if (!key_part->field->stored_in_db()) {