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.
parent cce2b45c
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;
...@@ -85,17 +85,6 @@ t1 CREATE TABLE `t1` ( ...@@ -85,17 +85,6 @@ t1 CREATE TABLE `t1` (
UNIQUE KEY `c2` (`c2`), UNIQUE KEY `c2` (`c2`),
UNIQUE KEY `c2_2` (`c2`) UNIQUE KEY `c2_2` (`c2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT ) 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); ALTER TABLE t1 DROP INDEX c2, ADD PRIMARY KEY(c1);
# session default # session default
SET DEBUG_SYNC = 'now WAIT_FOR scanned'; SET DEBUG_SYNC = 'now WAIT_FOR scanned';
......
--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;
...@@ -100,10 +100,6 @@ LOCK = SHARED, ALGORITHM = INPLACE; ...@@ -100,10 +100,6 @@ LOCK = SHARED, ALGORITHM = INPLACE;
ALTER TABLE t1 ADD UNIQUE INDEX(c2), ALTER TABLE t1 ADD UNIQUE INDEX(c2),
LOCK = EXCLUSIVE, ALGORITHM = INPLACE; 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; SHOW CREATE TABLE t1;
# Now the previous DEBUG_SYNC should kick in. # Now the previous DEBUG_SYNC should kick in.
--send --send
......
...@@ -6439,6 +6439,12 @@ static bool fill_alter_inplace_info(THD *thd, ...@@ -6439,6 +6439,12 @@ static bool fill_alter_inplace_info(THD *thd,
KEY *new_key; KEY *new_key;
KEY *new_key_end= KEY *new_key_end=
ha_alter_info->key_info_buffer + ha_alter_info->key_count; 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", DBUG_PRINT("info", ("index count old: %d new: %d",
table->s->keys, ha_alter_info->key_count)); table->s->keys, ha_alter_info->key_count));
...@@ -6513,6 +6519,17 @@ static bool fill_alter_inplace_info(THD *thd, ...@@ -6513,6 +6519,17 @@ static bool fill_alter_inplace_info(THD *thd,
new_field->field->field_index != key_part->fieldnr - 1) new_field->field->field_index != key_part->fieldnr - 1)
goto index_changed; 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; continue;
index_changed: index_changed:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment