diff --git a/mysql-test/suite/innodb/r/innodb-alter-timestamp.result b/mysql-test/suite/innodb/r/innodb-alter-timestamp.result index 56a1df7ce5d..6934484a488 100644 --- a/mysql-test/suite/innodb/r/innodb-alter-timestamp.result +++ b/mysql-test/suite/innodb/r/innodb-alter-timestamp.result @@ -124,3 +124,18 @@ SELECT DISTINCT (CURRENT_TIMESTAMP()-d4) <= 60 FROM t1; (CURRENT_TIMESTAMP()-d4) <= 60 1 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; diff --git a/mysql-test/suite/innodb/t/innodb-alter-timestamp.test b/mysql-test/suite/innodb/t/innodb-alter-timestamp.test index 1fabdc8f24d..28b09b18e10 100644 --- a/mysql-test/suite/innodb/t/innodb-alter-timestamp.test +++ b/mysql-test/suite/innodb/t/innodb-alter-timestamp.test @@ -1,4 +1,5 @@ --source include/have_innodb.inc +--source include/have_sequence.inc CREATE TABLE t1 (i1 INT UNSIGNED NULL DEFAULT 42) ENGINE=innodb; INSERT INTO t1 VALUES(NULL); @@ -82,3 +83,23 @@ ALTER TABLE t1 ADD COLUMN d4 TIMESTAMP DEFAULT CURRENT_TIMESTAMP; SELECT COUNT(DISTINCT d4),COUNT(d4),COUNT(*) FROM t1; SELECT DISTINCT (CURRENT_TIMESTAMP()-d4) <= 60 FROM 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; diff --git a/sql/handler.h b/sql/handler.h index 94c652359d2..656b376da8a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2352,11 +2352,14 @@ public: */ 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_info *alter_info_arg, KEY *key_info_arg, uint key_count_arg, partition_info *modified_part_info_arg, - bool ignore_arg) + bool ignore_arg, bool error_non_empty) : create_info(create_info_arg), alter_info(alter_info_arg), key_info_buffer(key_info_arg), @@ -2371,7 +2374,8 @@ public: modified_part_info(modified_part_info_arg), ignore(ignore_arg), online(false), - unsupported_reason(NULL) + unsupported_reason(NULL), + error_if_not_empty(error_non_empty) {} ~Alter_inplace_info() diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 86a93d4c8c9..ed1c3c401d3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9814,7 +9814,7 @@ do_continue:; Alter_inplace_info ha_alter_info(create_info, alter_info, key_info, key_count, IF_PARTITIONING(thd->work_part_info, NULL), - ignore); + ignore, alter_ctx.error_if_not_empty); TABLE *altered_table= NULL; bool use_inplace= true; @@ -10261,7 +10261,7 @@ err_new_table_cleanup: thd->abort_on_warning= true; make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN, f_val, strlength(f_val), t_type, - new_table->s, + new_table ? new_table->s : table->s, alter_ctx.datetime_field->field_name.str); thd->abort_on_warning= save_abort_on_warning; } diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index be6bc669349..0686c21c711 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -866,6 +866,63 @@ innobase_fts_check_doc_id_col( 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 @param altered_table TABLE object for new version of table. @param ha_alter_info Structure describing changes to be done @@ -1078,6 +1135,13 @@ ha_innobase::check_if_supported_inplace_alter( 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; /* If there is add or drop virtual columns, we will support operations