mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
MDEV-12586 ALTER TABLE…ALGORITHM=INPLACE fails with non-constant DEFAULT values
ha_innobase::check_if_supported_inplace_alter(): For now, reject ALGORITHM=INPLACE when a non-constant DEFAULT expression is specified for ADD COLUMN or for changing a NULL column to NOT NULL. Later, we should evaluate the non-constant column values in these cases.
This commit is contained in:
@ -2,7 +2,7 @@ CREATE TABLE t1 (
|
|||||||
`i1` INT(10) UNSIGNED NOT NULL,
|
`i1` INT(10) UNSIGNED NOT NULL,
|
||||||
`d1` TIMESTAMP NULL DEFAULT NULL
|
`d1` TIMESTAMP NULL DEFAULT NULL
|
||||||
) ENGINE=innodb;
|
) ENGINE=innodb;
|
||||||
show create table t1;
|
SHOW CREATE TABLE t1;
|
||||||
Table Create Table
|
Table Create Table
|
||||||
t1 CREATE TABLE `t1` (
|
t1 CREATE TABLE `t1` (
|
||||||
`i1` int(10) unsigned NOT NULL,
|
`i1` int(10) unsigned NOT NULL,
|
||||||
@ -25,5 +25,26 @@ CREATE TABLE t1 (
|
|||||||
) ENGINE=innodb;
|
) ENGINE=innodb;
|
||||||
INSERT INTO t1 (i1) VALUES (1), (2), (3), (4), (5);
|
INSERT INTO t1 (i1) VALUES (1), (2), (3), (4), (5);
|
||||||
ALTER TABLE t1 CHANGE `d1` `d1` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
ALTER TABLE t1 CHANGE `d1` `d1` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||||
drop table t1;
|
ALTER TABLE t1 ADD COLUMN d2 TIMESTAMP DEFAULT '2017-05-08 16:23:45',
|
||||||
set sql_mode = '';
|
LOCK=NONE;
|
||||||
|
ALTER TABLE t1 ADD COLUMN d3 TIMESTAMP DEFAULT d1, LOCK=NONE;
|
||||||
|
ERROR 0A000: LOCK=NONE is not supported for this operation. Try LOCK=SHARED
|
||||||
|
ALTER TABLE t1 ADD COLUMN d3 TIMESTAMP DEFAULT d1, ALGORITHM=INPLACE;
|
||||||
|
ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY
|
||||||
|
ALTER TABLE t1 ADD COLUMN d3 TIMESTAMP DEFAULT d1;
|
||||||
|
SELECT d1-d3, d2 FROM t1;
|
||||||
|
d1-d3 d2
|
||||||
|
0 2017-05-08 16:23:45
|
||||||
|
0 2017-05-08 16:23:45
|
||||||
|
0 2017-05-08 16:23:45
|
||||||
|
0 2017-05-08 16:23:45
|
||||||
|
0 2017-05-08 16:23:45
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`i1` int(10) unsigned NOT NULL,
|
||||||
|
`d1` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
`d2` timestamp NOT NULL DEFAULT '2017-05-08 16:23:45',
|
||||||
|
`d3` timestamp NOT NULL DEFAULT `d1`
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||||
|
DROP TABLE t1;
|
||||||
|
@ -5,7 +5,7 @@ CREATE TABLE t1 (
|
|||||||
`d1` TIMESTAMP NULL DEFAULT NULL
|
`d1` TIMESTAMP NULL DEFAULT NULL
|
||||||
) ENGINE=innodb;
|
) ENGINE=innodb;
|
||||||
|
|
||||||
show create table t1;
|
SHOW CREATE TABLE t1;
|
||||||
|
|
||||||
INSERT INTO t1 (i1) VALUES (1), (2), (3), (4), (5);
|
INSERT INTO t1 (i1) VALUES (1), (2), (3), (4), (5);
|
||||||
select * from t1;
|
select * from t1;
|
||||||
@ -19,9 +19,14 @@ CREATE TABLE t1 (
|
|||||||
) ENGINE=innodb;
|
) ENGINE=innodb;
|
||||||
INSERT INTO t1 (i1) VALUES (1), (2), (3), (4), (5);
|
INSERT INTO t1 (i1) VALUES (1), (2), (3), (4), (5);
|
||||||
ALTER TABLE t1 CHANGE `d1` `d1` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
ALTER TABLE t1 CHANGE `d1` `d1` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||||
drop table t1;
|
|
||||||
set sql_mode = '';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE t1 ADD COLUMN d2 TIMESTAMP DEFAULT '2017-05-08 16:23:45',
|
||||||
|
LOCK=NONE;
|
||||||
|
--error ER_ALTER_OPERATION_NOT_SUPPORTED
|
||||||
|
ALTER TABLE t1 ADD COLUMN d3 TIMESTAMP DEFAULT d1, LOCK=NONE;
|
||||||
|
--error ER_ALTER_OPERATION_NOT_SUPPORTED
|
||||||
|
ALTER TABLE t1 ADD COLUMN d3 TIMESTAMP DEFAULT d1, ALGORITHM=INPLACE;
|
||||||
|
ALTER TABLE t1 ADD COLUMN d3 TIMESTAMP DEFAULT d1;
|
||||||
|
SELECT d1-d3, d2 FROM t1;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
@ -722,35 +722,6 @@ ha_innobase::check_if_supported_inplace_alter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we have column that has changed from NULL -> NOT NULL
|
|
||||||
and column default has changed we need to do additional
|
|
||||||
check. */
|
|
||||||
if ((ha_alter_info->handler_flags
|
|
||||||
& Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE) &&
|
|
||||||
(ha_alter_info->handler_flags
|
|
||||||
& Alter_inplace_info::ALTER_COLUMN_DEFAULT)) {
|
|
||||||
Alter_info *alter_info = ha_alter_info->alter_info;
|
|
||||||
List_iterator<Create_field> def_it(alter_info->create_list);
|
|
||||||
Create_field *def;
|
|
||||||
while ((def=def_it++)) {
|
|
||||||
|
|
||||||
/* If this is first column definition whose SQL type
|
|
||||||
is TIMESTAMP and it is defined as NOT NULL and
|
|
||||||
it has either constant default or function default
|
|
||||||
we must use "Copy" method. */
|
|
||||||
if (is_timestamp_type(def->sql_type)) {
|
|
||||||
if ((def->flags & NOT_NULL_FLAG) != 0 && // NOT NULL
|
|
||||||
(def->default_value != NULL || // constant default ?
|
|
||||||
def->unireg_check != Field::NONE)) { // function default
|
|
||||||
ha_alter_info->unsupported_reason = innobase_get_err_msg(
|
|
||||||
ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL);
|
|
||||||
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ulint n_indexes = UT_LIST_GET_LEN((m_prebuilt->table)->indexes);
|
ulint n_indexes = UT_LIST_GET_LEN((m_prebuilt->table)->indexes);
|
||||||
|
|
||||||
/* If InnoDB dictionary and MySQL frm file are not consistent
|
/* If InnoDB dictionary and MySQL frm file are not consistent
|
||||||
@ -1035,6 +1006,72 @@ ha_innobase::check_if_supported_inplace_alter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* When changing a NULL column to NOT NULL and specifying a
|
||||||
|
DEFAULT value, ensure that the DEFAULT expression is a constant.
|
||||||
|
Also, in ADD COLUMN, for now we only support a
|
||||||
|
constant DEFAULT expression. */
|
||||||
|
cf_it.rewind();
|
||||||
|
Field **af = altered_table->field;
|
||||||
|
while (Create_field* cf = cf_it++) {
|
||||||
|
DBUG_ASSERT(cf->field
|
||||||
|
|| (ha_alter_info->handler_flags
|
||||||
|
& Alter_inplace_info::ADD_COLUMN));
|
||||||
|
|
||||||
|
if (const Field* f = cf->field) {
|
||||||
|
/* This could be changing an existing column
|
||||||
|
from NULL to NOT NULL. For now, ensure that
|
||||||
|
the DEFAULT is a constant. */
|
||||||
|
if (~ha_alter_info->handler_flags
|
||||||
|
& (Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE
|
||||||
|
| Alter_inplace_info::ALTER_COLUMN_DEFAULT)
|
||||||
|
|| (*af)->real_maybe_null()) {
|
||||||
|
/* This ALTER TABLE is not both changing
|
||||||
|
a column to NOT NULL and changing the
|
||||||
|
DEFAULT value of a column, or this column
|
||||||
|
does allow NULL after the ALTER TABLE. */
|
||||||
|
goto next_column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the matching column in the old table. */
|
||||||
|
Field** fp;
|
||||||
|
for (fp = table->field; *fp; fp++) {
|
||||||
|
if (f != *fp) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!f->real_maybe_null()) {
|
||||||
|
/* The column already is NOT NULL. */
|
||||||
|
goto next_column;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The column must be found in the old table. */
|
||||||
|
DBUG_ASSERT(fp < &table->field[table->s->fields]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(*af)->default_value
|
||||||
|
|| (*af)->default_value->flags == 0) {
|
||||||
|
/* The NOT NULL column is not
|
||||||
|
carrying a non-constant DEFAULT. */
|
||||||
|
goto next_column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Allow NULL column values to
|
||||||
|
be replaced with a non-constant DEFAULT. */
|
||||||
|
if (cf->field) {
|
||||||
|
ha_alter_info->unsupported_reason
|
||||||
|
= innobase_get_err_msg(
|
||||||
|
ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
|
||||||
|
|
||||||
|
next_column:
|
||||||
|
af++;
|
||||||
|
}
|
||||||
|
|
||||||
|
cf_it.rewind();
|
||||||
|
|
||||||
DBUG_RETURN(online
|
DBUG_RETURN(online
|
||||||
? HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE
|
? HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE
|
||||||
: HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE);
|
: HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE);
|
||||||
|
Reference in New Issue
Block a user