summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThirunarayanan Balathandayuthapani <thiru@mariadb.com>2019-11-23 12:51:53 +0530
committerThirunarayanan Balathandayuthapani <thiru@mariadb.com>2019-11-23 12:56:01 +0530
commitcc229a01dc94ea00691dee1e268ad489339a84b7 (patch)
treecacfdc5d28c8c97b00c3f69671d57e5667b995bc
parent6cedb671e99038f1a10e0d8504f835aaabed9780 (diff)
downloadmariadb-git-bb-10.4-MDEV-20190.tar.gz
MDEV-20190 Instant operation fails when add column and collation change on non-indexed columnbb-10.4-MDEV-20190
- Relax the debug assertion when doing instant operation on collation changed column.
-rw-r--r--mysql-test/suite/innodb/r/instant_alter_bugs.result23
-rw-r--r--mysql-test/suite/innodb/t/instant_alter_bugs.test17
-rw-r--r--storage/innobase/data/data0type.cc17
-rw-r--r--storage/innobase/handler/handler0alter.cc5
-rw-r--r--storage/innobase/include/data0type.h4
-rw-r--r--storage/innobase/include/dict0mem.h38
6 files changed, 93 insertions, 11 deletions
diff --git a/mysql-test/suite/innodb/r/instant_alter_bugs.result b/mysql-test/suite/innodb/r/instant_alter_bugs.result
index 19262246c9b..78104e1dfa2 100644
--- a/mysql-test/suite/innodb/r/instant_alter_bugs.result
+++ b/mysql-test/suite/innodb/r/instant_alter_bugs.result
@@ -324,4 +324,27 @@ InnoDB 0 transactions not purged
SELECT * FROM t1;
a
DROP TABLE t1;
+#
+# MDEV-20190 Instant operation fails when add column and collation
+# change on non-indexed column
+#
+CREATE TABLE t1 (a CHAR)ENGINE=INNODB;
+ALTER TABLE t1 DEFAULT COLLATE= latin1_general_cs;
+ALTER TABLE t1 ADD COLUMN b INT NOT NULL, MODIFY a CHAR, ALGORITHM=INSTANT;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(1) COLLATE latin1_general_cs DEFAULT NULL,
+ `b` int(11) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs
+DROP TABLE t1;
+CREATE TABLE t1 (a CHAR NOT NULL) ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
+ALTER TABLE t1 DEFAULT COLLATE = latin1_general_cs;
+ALTER TABLE t1 MODIFY a CHAR, ALGORITHM=INSTANT;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(1) COLLATE latin1_general_cs DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs ROW_FORMAT=REDUNDANT
+DROP TABLE t1;
SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency;
diff --git a/mysql-test/suite/innodb/t/instant_alter_bugs.test b/mysql-test/suite/innodb/t/instant_alter_bugs.test
index 090a4aef787..2b47e5bd135 100644
--- a/mysql-test/suite/innodb/t/instant_alter_bugs.test
+++ b/mysql-test/suite/innodb/t/instant_alter_bugs.test
@@ -348,4 +348,21 @@ ALTER TABLE t1 DROP b, DROP c, DROP d, DROP e;
--source include/wait_all_purged.inc
SELECT * FROM t1;
DROP TABLE t1;
+
+--echo #
+--echo # MDEV-20190 Instant operation fails when add column and collation
+--echo # change on non-indexed column
+--echo #
+
+CREATE TABLE t1 (a CHAR)ENGINE=INNODB;
+ALTER TABLE t1 DEFAULT COLLATE= latin1_general_cs;
+ALTER TABLE t1 ADD COLUMN b INT NOT NULL, MODIFY a CHAR, ALGORITHM=INSTANT;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a CHAR NOT NULL) ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
+ALTER TABLE t1 DEFAULT COLLATE = latin1_general_cs;
+ALTER TABLE t1 MODIFY a CHAR, ALGORITHM=INSTANT;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency;
diff --git a/storage/innobase/data/data0type.cc b/storage/innobase/data/data0type.cc
index 7de4cc026d1..0f55b76bd09 100644
--- a/storage/innobase/data/data0type.cc
+++ b/storage/innobase/data/data0type.cc
@@ -209,4 +209,21 @@ dtype_print(const dtype_t* type)
fprintf(stderr, " len %lu", (ulong) len);
}
+
#endif /* UNIV_DEBUG */
+
+bool dtype_is_latin1(ulint prtype)
+{
+ switch (dtype_get_charset_coll(prtype)) {
+ case 5: /* latin1_german1_ci */
+ case 8: /* latin1_swedish_ci */
+ case 15: /* latin1_danish_ci */
+ case 31: /* latin1_german2_ci */
+ case 47: /* latin1_bin */
+ case 48: /* latin1_general_ci */
+ case 49: /* latin1_general_cs */
+ case 94: /* latin1_spanish_ci */
+ return true;
+ }
+ return false;
+}
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 7bb226b9a2e..e250ea358cf 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -537,10 +537,7 @@ inline bool dict_table_t::instant_column(const dict_table_t& table,
if (const dict_col_t* o = find(old_cols, col_map, n_cols, i)) {
c.def_val = o->def_val;
- DBUG_ASSERT(!((c.prtype ^ o->prtype)
- & ~(DATA_NOT_NULL | DATA_VERSIONED
- | DATA_LONG_TRUE_VARCHAR)));
- DBUG_ASSERT(c.mtype == o->mtype);
+ DBUG_ASSERT(o->same_mtype(c));
DBUG_ASSERT(c.len >= o->len);
if (o->vers_sys_start()) {
diff --git a/storage/innobase/include/data0type.h b/storage/innobase/include/data0type.h
index 7168c104b1c..cf029390499 100644
--- a/storage/innobase/include/data0type.h
+++ b/storage/innobase/include/data0type.h
@@ -505,6 +505,10 @@ dtype_print(
const dtype_t* type);
#endif /* UNIV_DEBUG */
+/** Determine if a MySQL string type is a subset of latin1.
+@return whether a subset of latin1 */
+bool dtype_is_latin1(ulint prtype);
+
/* Structure for an SQL data type.
If you add fields to this structure, be sure to initialize them everywhere.
This structure is initialized in the following functions:
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 5e1fa0033f7..5849b1f1be7 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -674,19 +674,43 @@ public:
def_val.data = NULL;
}
+ /** Determine if the columns have same mtype.
+ @param[in] other column to compare to
+ @return whether the column have the same mtype. */
+ bool same_mtype(const dict_col_t& other) const {
+ if (mtype == other.mtype)
+ return true;
+
+ /* DATA_CHAR and DATA_VARCHAR can be changed to
+ DATA_MYSQL and DATA_VARMYSQL if charset is of type latin1
+ and when collate is changed to/from latin_swedish_ci. */
+ if (dtype_is_latin1(prtype) && dtype_is_latin1(other.prtype))
+ {
+ if (dtype_get_charset_coll(prtype)
+ == dtype_get_charset_coll(other.prtype))
+ return false;
+
+ if ((mtype == DATA_VARCHAR && other.mtype == DATA_VARMYSQL)
+ || (mtype == DATA_VARMYSQL && other.mtype == DATA_VARCHAR)
+ || (mtype == DATA_CHAR && other.mtype == DATA_MYSQL)
+ || (mtype == DATA_MYSQL && other.mtype == DATA_CHAR))
+ return true;
+ }
+ return false;
+ }
+
/** Determine if the columns have the same format
except for is_nullable() and is_versioned().
@param[in] other column to compare to
@return whether the columns have the same format */
bool same_format(const dict_col_t& other) const
{
- return mtype == other.mtype
- && len >= other.len
- && mbminlen == other.mbminlen
- && mbmaxlen == other.mbmaxlen
- && !((prtype ^ other.prtype)
- & ~(DATA_NOT_NULL | DATA_VERSIONED
- | DATA_LONG_TRUE_VARCHAR));
+ if (!same_mtype(other))
+ return false;
+
+ return len >= other.len
+ && mbminlen == other.mbminlen
+ && mbmaxlen == other.mbmaxlen;
}
};