diff options
author | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2019-01-24 13:52:51 +0530 |
---|---|---|
committer | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2019-01-24 13:52:51 +0530 |
commit | a0f3b9f94f3094ccb9ce75c53b25d36c4c78e922 (patch) | |
tree | 78554281d9e2b560cddf6b3835e7659e6858f102 | |
parent | cce2b45c8f5b3245d2e63d2763aeec59153d2c6f (diff) | |
download | mariadb-git-a0f3b9f94f3094ccb9ce75c53b25d36c4c78e922.tar.gz |
MDEV-17376 Server fails to set ADD_PK_INDEX, DROP_PK_INDEX if unique index nominated as PK
Problem:
========
Server fails to notify the engine by not setting the ADD_PK_INDEX and
DROP_PK_INDEX When there is a
i) Change in candidate for primary key.
ii) New candidate for primary key.
Fix:
====
Server sets the ADD_PK_INDEX and DROP_PK_INDEX while doing alter for the
above problematic case.
-rw-r--r-- | mysql-test/suite/innodb/r/alter_candidate_key.result | 107 | ||||
-rw-r--r-- | mysql-test/suite/innodb/r/innodb-table-online.result | 11 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/alter_candidate_key.test | 72 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/innodb-table-online.test | 4 | ||||
-rw-r--r-- | sql/sql_table.cc | 17 |
5 files changed, 196 insertions, 15 deletions
diff --git a/mysql-test/suite/innodb/r/alter_candidate_key.result b/mysql-test/suite/innodb/r/alter_candidate_key.result new file mode 100644 index 00000000000..b0b8e390c7e --- /dev/null +++ b/mysql-test/suite/innodb/r/alter_candidate_key.result @@ -0,0 +1,107 @@ +CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL, +UNIQUE KEY uidx2(f1,f2), +UNIQUE KEY uidx1(f2)) ENGINE=InnoDB; +INSERT INTO t1 VALUES(1, 1); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) NOT NULL, + `f2` int(11) NOT NULL, + UNIQUE KEY `uidx2` (`f1`,`f2`), + UNIQUE KEY `uidx1` (`f2`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SET DEBUG_SYNC = 'innodb_inplace_alter_table_enter + SIGNAL conc_dml WAIT_FOR go_ahead'; +ALTER TABLE t1 CHANGE COLUMN f1 f11 INT, ALGORITHM=INPLACE; +SET DEBUG_SYNC = 'now WAIT_FOR conc_dml'; +DELETE FROM t1; +SET DEBUG_SYNC = 'now SIGNAL go_ahead'; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f11` int(11) DEFAULT NULL, + `f2` int(11) NOT NULL, + UNIQUE KEY `uidx1` (`f2`), + UNIQUE KEY `uidx2` (`f11`,`f2`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; +CREATE TABLE t1(f1 INT, f2 INT, +PRIMARY KEY(f1, f2), +UNIQUE INDEX uidx2 (f1, f2), +UNIQUE INDEX uidx1 (f2))ENGINE=InnoDB; +ALTER TABLE t1 DROP PRIMARY KEY; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) NOT NULL DEFAULT '0', + `f2` int(11) NOT NULL DEFAULT '0', + UNIQUE KEY `uidx2` (`f1`,`f2`), + UNIQUE KEY `uidx1` (`f2`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SET DEBUG_SYNC = 'innodb_inplace_alter_table_enter + SIGNAL conc_dml WAIT_FOR go_ahead'; +ALTER TABLE t1 CHANGE COLUMN f1 f11 INT, ALGORITHM=INPLACE; +SET DEBUG_SYNC = 'now WAIT_FOR conc_dml'; +INSERT INTO t1 VALUES(1, 1), (1, 1); +ERROR 23000: Duplicate entry '1-1' for key 'uidx2' +SET DEBUG_SYNC = 'now SIGNAL go_ahead'; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f11` int(11) DEFAULT NULL, + `f2` int(11) NOT NULL DEFAULT '0', + UNIQUE KEY `uidx1` (`f2`), + UNIQUE KEY `uidx2` (`f11`,`f2`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; +SET SQL_MODE= strict_trans_tables; +CREATE TABLE t1(a INT UNIQUE) ENGINE=InnoDB; +SET DEBUG_SYNC='row_log_table_apply1_before SIGNAL dml WAIT_FOR dml_done'; +ALTER TABLE t1 MODIFY COLUMN a INT NOT NULL; +SET DEBUG_SYNC='now WAIT_FOR dml'; +BEGIN; +INSERT INTO t1 SET a=NULL; +ROLLBACK; +set DEBUG_SYNC='now SIGNAL dml_done'; +ERROR 22004: Invalid use of NULL value +DROP TABLE t1; +SET DEBUG_SYNC="RESET"; +SET SQL_MODE=DEFAULT; +CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY(f1, f2), +UNIQUE KEY(f2))ENGINE=InnoDB; +ALTER TABLE t1 DROP PRIMARY KEY; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) NOT NULL, + `f2` int(11) NOT NULL, + UNIQUE KEY `f2` (`f2`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL, +UNIQUE KEY(f2), UNIQUE KEY(f2))ENGINE=InnoDB; +Warnings: +Note 1831 Duplicate index `f2_2`. This is deprecated and will be disallowed in a future release. +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) NOT NULL, + `f2` int(11) NOT NULL, + UNIQUE KEY `f2` (`f2`), + UNIQUE KEY `f2_2` (`f2`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +ALTER TABLE t1 DROP INDEX f2, ALGORITHM=INPLACE; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) NOT NULL, + `f2` int(11) NOT NULL, + UNIQUE KEY `f2_2` (`f2`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/innodb-table-online.result b/mysql-test/suite/innodb/r/innodb-table-online.result index eb55ba57e36..0a8d1c2fefb 100644 --- a/mysql-test/suite/innodb/r/innodb-table-online.result +++ b/mysql-test/suite/innodb/r/innodb-table-online.result @@ -85,17 +85,6 @@ t1 CREATE TABLE `t1` ( UNIQUE KEY `c2` (`c2`), UNIQUE KEY `c2_2` (`c2`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT -ALTER TABLE t1 DROP INDEX c2, ALGORITHM = INPLACE; -ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Dropping a primary key is not allowed without also adding a new primary key. Try ALGORITHM=COPY. -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` int(11) NOT NULL, - `c2` int(11) NOT NULL, - `c3` text NOT NULL, - UNIQUE KEY `c2` (`c2`), - UNIQUE KEY `c2_2` (`c2`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT ALTER TABLE t1 DROP INDEX c2, ADD PRIMARY KEY(c1); # session default SET DEBUG_SYNC = 'now WAIT_FOR scanned'; diff --git a/mysql-test/suite/innodb/t/alter_candidate_key.test b/mysql-test/suite/innodb/t/alter_candidate_key.test new file mode 100644 index 00000000000..7429cd89a1a --- /dev/null +++ b/mysql-test/suite/innodb/t/alter_candidate_key.test @@ -0,0 +1,72 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL, + UNIQUE KEY uidx2(f1,f2), + UNIQUE KEY uidx1(f2)) ENGINE=InnoDB; +INSERT INTO t1 VALUES(1, 1); +SHOW CREATE TABLE t1; +SET DEBUG_SYNC = 'innodb_inplace_alter_table_enter + SIGNAL conc_dml WAIT_FOR go_ahead'; +--send ALTER TABLE t1 CHANGE COLUMN f1 f11 INT, ALGORITHM=INPLACE +connect (con1,localhost,root,,); +SET DEBUG_SYNC = 'now WAIT_FOR conc_dml'; +DELETE FROM t1; +SET DEBUG_SYNC = 'now SIGNAL go_ahead'; +connection default; +reap; +SHOW CREATE TABLE t1; +CHECK TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1(f1 INT, f2 INT, + PRIMARY KEY(f1, f2), + UNIQUE INDEX uidx2 (f1, f2), + UNIQUE INDEX uidx1 (f2))ENGINE=InnoDB; +ALTER TABLE t1 DROP PRIMARY KEY; +SHOW CREATE TABLE t1; +SET DEBUG_SYNC = 'innodb_inplace_alter_table_enter + SIGNAL conc_dml WAIT_FOR go_ahead'; +--send ALTER TABLE t1 CHANGE COLUMN f1 f11 INT, ALGORITHM=INPLACE +connection con1; +SET DEBUG_SYNC = 'now WAIT_FOR conc_dml'; +--error ER_DUP_ENTRY +INSERT INTO t1 VALUES(1, 1), (1, 1); +SET DEBUG_SYNC = 'now SIGNAL go_ahead'; +connection default; +reap; +SHOW CREATE TABLE t1; +CHECK TABLE t1; +DROP TABLE t1; + +SET SQL_MODE= strict_trans_tables; +CREATE TABLE t1(a INT UNIQUE) ENGINE=InnoDB; +SET DEBUG_SYNC='row_log_table_apply1_before SIGNAL dml WAIT_FOR dml_done'; +--send ALTER TABLE t1 MODIFY COLUMN a INT NOT NULL +connection con1; +SET DEBUG_SYNC='now WAIT_FOR dml'; +BEGIN; +INSERT INTO t1 SET a=NULL; +ROLLBACK; +set DEBUG_SYNC='now SIGNAL dml_done'; +connection default; +--error ER_INVALID_USE_OF_NULL +reap; +DROP TABLE t1; +disconnect con1; +SET DEBUG_SYNC="RESET"; +SET SQL_MODE=DEFAULT; + +CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY(f1, f2), + UNIQUE KEY(f2))ENGINE=InnoDB; +ALTER TABLE t1 DROP PRIMARY KEY; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL, + UNIQUE KEY(f2), UNIQUE KEY(f2))ENGINE=InnoDB; +SHOW CREATE TABLE t1; +ALTER TABLE t1 DROP INDEX f2, ALGORITHM=INPLACE; +SHOW CREATE TABLE t1; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/innodb-table-online.test b/mysql-test/suite/innodb/t/innodb-table-online.test index 4e9f2f13344..b0711412a52 100644 --- a/mysql-test/suite/innodb/t/innodb-table-online.test +++ b/mysql-test/suite/innodb/t/innodb-table-online.test @@ -101,10 +101,6 @@ ALTER TABLE t1 ADD UNIQUE INDEX(c2), LOCK = EXCLUSIVE, ALGORITHM = INPLACE; SHOW CREATE TABLE t1; -# We do not support plain DROP_PK_INDEX without ADD_PK_INDEX. ---error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON -ALTER TABLE t1 DROP INDEX c2, ALGORITHM = INPLACE; -SHOW CREATE TABLE t1; # Now the previous DEBUG_SYNC should kick in. --send ALTER TABLE t1 DROP INDEX c2, ADD PRIMARY KEY(c1); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2302026b18b..df1ff8eaf5d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6439,6 +6439,12 @@ static bool fill_alter_inplace_info(THD *thd, KEY *new_key; KEY *new_key_end= ha_alter_info->key_info_buffer + ha_alter_info->key_count; + /* + Primary key index for the new table + */ + const KEY* const new_pk= (ha_alter_info->key_count > 0 && + is_candidate_key(ha_alter_info->key_info_buffer)) ? + ha_alter_info->key_info_buffer : NULL; DBUG_PRINT("info", ("index count old: %d new: %d", table->s->keys, ha_alter_info->key_count)); @@ -6513,6 +6519,17 @@ static bool fill_alter_inplace_info(THD *thd, new_field->field->field_index != key_part->fieldnr - 1) goto index_changed; } + + /* + Rebuild the index if following condition get satisfied: + + (i) Old table doesn't have primary key, new table has it and vice-versa + (ii) Primary key changed to another existing index + */ + if ((new_key == new_pk) != + ((uint) (table_key - table->key_info) == table->s->primary_key)) + goto index_changed; + continue; index_changed: |