MDEV-19611 INPLACE ALTER does not fail on bad implicit default value

- Inplace alter shouldn't set default date column as '0000-00-00' when
table is not empty. So mysql_inplace_alter_table() copied
alter_ctx.error_if_not_empty to a new field of Alter_inplace_info.
In ha_innobase::check_if_supported_inplace_alter() should check the
error_if_not_empty flag and return INPLACE_NOT_SUPPORTED if the table
is not empty
parent 3568fad5
...@@ -124,3 +124,18 @@ SELECT DISTINCT (CURRENT_TIMESTAMP()-d4) <= 60 FROM t1; ...@@ -124,3 +124,18 @@ SELECT DISTINCT (CURRENT_TIMESTAMP()-d4) <= 60 FROM t1;
(CURRENT_TIMESTAMP()-d4) <= 60 (CURRENT_TIMESTAMP()-d4) <= 60
1 1
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1(f1 int) ENGINE=InnoDB;
INSERT INTO t1 SELECT * FROM seq_1_to_4096;
connect purge_control,localhost,root,,;
START TRANSACTION WITH CONSISTENT SNAPSHOT;
connection default;
DELETE FROM t1;
SET sql_mode='STRICT_ALL_TABLES,STRICT_TRANS_TABLES,NO_ZERO_DATE';
ALTER TABLE t1 ADD f2 DATE NOT NULL, ALGORITHM=INPLACE;
INSERT INTO t1 VALUES (1, now());
Warnings:
Note 1265 Data truncated for column 'f2' at row 1
ALTER TABLE t1 ADD f3 DATE NOT NULL, ALGORITHM=INPLACE;
ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY
DROP TABLE t1;
disconnect purge_control;
--source include/have_innodb.inc --source include/have_innodb.inc
--source include/have_sequence.inc
CREATE TABLE t1 (i1 INT UNSIGNED NULL DEFAULT 42) ENGINE=innodb; CREATE TABLE t1 (i1 INT UNSIGNED NULL DEFAULT 42) ENGINE=innodb;
INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES(NULL);
...@@ -82,3 +83,23 @@ ALTER TABLE t1 ADD COLUMN d4 TIMESTAMP DEFAULT CURRENT_TIMESTAMP; ...@@ -82,3 +83,23 @@ ALTER TABLE t1 ADD COLUMN d4 TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
SELECT COUNT(DISTINCT d4),COUNT(d4),COUNT(*) FROM t1; SELECT COUNT(DISTINCT d4),COUNT(d4),COUNT(*) FROM t1;
SELECT DISTINCT (CURRENT_TIMESTAMP()-d4) <= 60 FROM t1; SELECT DISTINCT (CURRENT_TIMESTAMP()-d4) <= 60 FROM t1;
DROP TABLE t1; DROP TABLE t1;
# MDEV-19611 INPLACE ALTER does not fail on bad implicit default value
# Empty-table
CREATE TABLE t1(f1 int) ENGINE=InnoDB;
INSERT INTO t1 SELECT * FROM seq_1_to_4096;
connect(purge_control,localhost,root,,);
START TRANSACTION WITH CONSISTENT SNAPSHOT;
connection default;
DELETE FROM t1;
SET sql_mode='STRICT_ALL_TABLES,STRICT_TRANS_TABLES,NO_ZERO_DATE';
ALTER TABLE t1 ADD f2 DATE NOT NULL, ALGORITHM=INPLACE;
# Non-empty table
INSERT INTO t1 VALUES (1, now());
--error ER_ALTER_OPERATION_NOT_SUPPORTED
ALTER TABLE t1 ADD f3 DATE NOT NULL, ALGORITHM=INPLACE;
DROP TABLE t1;
disconnect purge_control;
...@@ -2352,11 +2352,14 @@ class Alter_inplace_info ...@@ -2352,11 +2352,14 @@ class Alter_inplace_info
*/ */
const char *unsupported_reason; const char *unsupported_reason;
/** true when InnoDB should abort the alter when table is not empty */
bool error_if_not_empty;
Alter_inplace_info(HA_CREATE_INFO *create_info_arg, Alter_inplace_info(HA_CREATE_INFO *create_info_arg,
Alter_info *alter_info_arg, Alter_info *alter_info_arg,
KEY *key_info_arg, uint key_count_arg, KEY *key_info_arg, uint key_count_arg,
partition_info *modified_part_info_arg, partition_info *modified_part_info_arg,
bool ignore_arg) bool ignore_arg, bool error_non_empty)
: create_info(create_info_arg), : create_info(create_info_arg),
alter_info(alter_info_arg), alter_info(alter_info_arg),
key_info_buffer(key_info_arg), key_info_buffer(key_info_arg),
...@@ -2371,7 +2374,8 @@ class Alter_inplace_info ...@@ -2371,7 +2374,8 @@ class Alter_inplace_info
modified_part_info(modified_part_info_arg), modified_part_info(modified_part_info_arg),
ignore(ignore_arg), ignore(ignore_arg),
online(false), online(false),
unsupported_reason(NULL) unsupported_reason(NULL),
error_if_not_empty(error_non_empty)
{} {}
~Alter_inplace_info() ~Alter_inplace_info()
......
...@@ -9814,7 +9814,7 @@ do_continue:; ...@@ -9814,7 +9814,7 @@ do_continue:;
Alter_inplace_info ha_alter_info(create_info, alter_info, Alter_inplace_info ha_alter_info(create_info, alter_info,
key_info, key_count, key_info, key_count,
IF_PARTITIONING(thd->work_part_info, NULL), IF_PARTITIONING(thd->work_part_info, NULL),
ignore); ignore, alter_ctx.error_if_not_empty);
TABLE *altered_table= NULL; TABLE *altered_table= NULL;
bool use_inplace= true; bool use_inplace= true;
...@@ -10261,7 +10261,7 @@ do_continue:; ...@@ -10261,7 +10261,7 @@ do_continue:;
thd->abort_on_warning= true; thd->abort_on_warning= true;
make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN, make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN,
f_val, strlength(f_val), t_type, f_val, strlength(f_val), t_type,
new_table->s, new_table ? new_table->s : table->s,
alter_ctx.datetime_field->field_name.str); alter_ctx.datetime_field->field_name.str);
thd->abort_on_warning= save_abort_on_warning; thd->abort_on_warning= save_abort_on_warning;
} }
......
...@@ -866,6 +866,63 @@ innobase_fts_check_doc_id_col( ...@@ -866,6 +866,63 @@ innobase_fts_check_doc_id_col(
return(false); return(false);
} }
/** Check whether the table is empty.
@param[in] table table to be checked
@return true if table is empty */
static bool innobase_table_is_empty(const dict_table_t *table)
{
dict_index_t *clust_index= dict_table_get_first_index(table);
mtr_t mtr;
btr_pcur_t pcur;
buf_block_t *block;
page_cur_t *cur;
const rec_t *rec;
bool next_page= false;
mtr.start();
btr_pcur_open_at_index_side(true, clust_index, BTR_SEARCH_LEAF,
&pcur, true, 0, &mtr);
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
if (!rec_is_metadata(btr_pcur_get_rec(&pcur), clust_index))
btr_pcur_move_to_prev_on_page(&pcur);
scan_leaf:
cur= btr_pcur_get_page_cur(&pcur);
page_cur_move_to_next(cur);
next_page:
if (next_page)
{
uint32_t next_page_no= btr_page_get_next(page_cur_get_page(cur));
if (next_page_no == FIL_NULL)
{
mtr.commit();
return true;
}
next_page= false;
block= page_cur_get_block(cur);
block= btr_block_get(page_id_t(block->page.id.space(), next_page_no),
block->page.size, BTR_SEARCH_LEAF, clust_index,
&mtr);
btr_leaf_page_release(page_cur_get_block(cur), BTR_SEARCH_LEAF, &mtr);
page_cur_set_before_first(block, cur);
page_cur_move_to_next(cur);
}
rec= page_cur_get_rec(cur);
if (rec_get_deleted_flag(rec, dict_table_is_comp(table)));
else if (!page_rec_is_supremum(rec))
{
mtr.commit();
return false;
}
else
{
next_page= true;
goto next_page;
}
goto scan_leaf;
}
/** Check if InnoDB supports a particular alter table in-place /** Check if InnoDB supports a particular alter table in-place
@param altered_table TABLE object for new version of table. @param altered_table TABLE object for new version of table.
@param ha_alter_info Structure describing changes to be done @param ha_alter_info Structure describing changes to be done
...@@ -1078,6 +1135,13 @@ ha_innobase::check_if_supported_inplace_alter( ...@@ -1078,6 +1135,13 @@ ha_innobase::check_if_supported_inplace_alter(
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
} }
/* '0000-00-00' value isn't allowed for datetime datatype
for newly added column when table is not empty */
if (ha_alter_info->error_if_not_empty
&& !innobase_table_is_empty(m_prebuilt->table)) {
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
}
bool add_drop_v_cols = false; bool add_drop_v_cols = false;
/* If there is add or drop virtual columns, we will support operations /* If there is add or drop virtual columns, we will support operations
......
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