Skip to content

Commit c755974

Browse files
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
1 parent 3568fad commit c755974

File tree

5 files changed

+108
-4
lines changed

5 files changed

+108
-4
lines changed

mysql-test/suite/innodb/r/innodb-alter-timestamp.result

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,18 @@ SELECT DISTINCT (CURRENT_TIMESTAMP()-d4) <= 60 FROM t1;
124124
(CURRENT_TIMESTAMP()-d4) <= 60
125125
1
126126
DROP TABLE t1;
127+
CREATE TABLE t1(f1 int) ENGINE=InnoDB;
128+
INSERT INTO t1 SELECT * FROM seq_1_to_4096;
129+
connect purge_control,localhost,root,,;
130+
START TRANSACTION WITH CONSISTENT SNAPSHOT;
131+
connection default;
132+
DELETE FROM t1;
133+
SET sql_mode='STRICT_ALL_TABLES,STRICT_TRANS_TABLES,NO_ZERO_DATE';
134+
ALTER TABLE t1 ADD f2 DATE NOT NULL, ALGORITHM=INPLACE;
135+
INSERT INTO t1 VALUES (1, now());
136+
Warnings:
137+
Note 1265 Data truncated for column 'f2' at row 1
138+
ALTER TABLE t1 ADD f3 DATE NOT NULL, ALGORITHM=INPLACE;
139+
ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY
140+
DROP TABLE t1;
141+
disconnect purge_control;

mysql-test/suite/innodb/t/innodb-alter-timestamp.test

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
--source include/have_innodb.inc
2+
--source include/have_sequence.inc
23

34
CREATE TABLE t1 (i1 INT UNSIGNED NULL DEFAULT 42) ENGINE=innodb;
45
INSERT INTO t1 VALUES(NULL);
@@ -82,3 +83,23 @@ ALTER TABLE t1 ADD COLUMN d4 TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
8283
SELECT COUNT(DISTINCT d4),COUNT(d4),COUNT(*) FROM t1;
8384
SELECT DISTINCT (CURRENT_TIMESTAMP()-d4) <= 60 FROM t1;
8485
DROP TABLE t1;
86+
87+
# MDEV-19611 INPLACE ALTER does not fail on bad implicit default value
88+
89+
# Empty-table
90+
CREATE TABLE t1(f1 int) ENGINE=InnoDB;
91+
INSERT INTO t1 SELECT * FROM seq_1_to_4096;
92+
connect(purge_control,localhost,root,,);
93+
START TRANSACTION WITH CONSISTENT SNAPSHOT;
94+
95+
connection default;
96+
DELETE FROM t1;
97+
SET sql_mode='STRICT_ALL_TABLES,STRICT_TRANS_TABLES,NO_ZERO_DATE';
98+
ALTER TABLE t1 ADD f2 DATE NOT NULL, ALGORITHM=INPLACE;
99+
100+
# Non-empty table
101+
INSERT INTO t1 VALUES (1, now());
102+
--error ER_ALTER_OPERATION_NOT_SUPPORTED
103+
ALTER TABLE t1 ADD f3 DATE NOT NULL, ALGORITHM=INPLACE;
104+
DROP TABLE t1;
105+
disconnect purge_control;

sql/handler.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,11 +2352,14 @@ class Alter_inplace_info
23522352
*/
23532353
const char *unsupported_reason;
23542354

2355+
/** true when InnoDB should abort the alter when table is not empty */
2356+
bool error_if_not_empty;
2357+
23552358
Alter_inplace_info(HA_CREATE_INFO *create_info_arg,
23562359
Alter_info *alter_info_arg,
23572360
KEY *key_info_arg, uint key_count_arg,
23582361
partition_info *modified_part_info_arg,
2359-
bool ignore_arg)
2362+
bool ignore_arg, bool error_non_empty)
23602363
: create_info(create_info_arg),
23612364
alter_info(alter_info_arg),
23622365
key_info_buffer(key_info_arg),
@@ -2371,7 +2374,8 @@ class Alter_inplace_info
23712374
modified_part_info(modified_part_info_arg),
23722375
ignore(ignore_arg),
23732376
online(false),
2374-
unsupported_reason(NULL)
2377+
unsupported_reason(NULL),
2378+
error_if_not_empty(error_non_empty)
23752379
{}
23762380

23772381
~Alter_inplace_info()

sql/sql_table.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9814,7 +9814,7 @@ do_continue:;
98149814
Alter_inplace_info ha_alter_info(create_info, alter_info,
98159815
key_info, key_count,
98169816
IF_PARTITIONING(thd->work_part_info, NULL),
9817-
ignore);
9817+
ignore, alter_ctx.error_if_not_empty);
98189818
TABLE *altered_table= NULL;
98199819
bool use_inplace= true;
98209820

@@ -10261,7 +10261,7 @@ do_continue:;
1026110261
thd->abort_on_warning= true;
1026210262
make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN,
1026310263
f_val, strlength(f_val), t_type,
10264-
new_table->s,
10264+
new_table ? new_table->s : table->s,
1026510265
alter_ctx.datetime_field->field_name.str);
1026610266
thd->abort_on_warning= save_abort_on_warning;
1026710267
}

storage/innobase/handler/handler0alter.cc

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,63 @@ innobase_fts_check_doc_id_col(
866866
return(false);
867867
}
868868

869+
/** Check whether the table is empty.
870+
@param[in] table table to be checked
871+
@return true if table is empty */
872+
static bool innobase_table_is_empty(const dict_table_t *table)
873+
{
874+
dict_index_t *clust_index= dict_table_get_first_index(table);
875+
mtr_t mtr;
876+
btr_pcur_t pcur;
877+
buf_block_t *block;
878+
page_cur_t *cur;
879+
const rec_t *rec;
880+
bool next_page= false;
881+
882+
mtr.start();
883+
btr_pcur_open_at_index_side(true, clust_index, BTR_SEARCH_LEAF,
884+
&pcur, true, 0, &mtr);
885+
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
886+
if (!rec_is_metadata(btr_pcur_get_rec(&pcur), clust_index))
887+
btr_pcur_move_to_prev_on_page(&pcur);
888+
scan_leaf:
889+
cur= btr_pcur_get_page_cur(&pcur);
890+
page_cur_move_to_next(cur);
891+
next_page:
892+
if (next_page)
893+
{
894+
uint32_t next_page_no= btr_page_get_next(page_cur_get_page(cur));
895+
if (next_page_no == FIL_NULL)
896+
{
897+
mtr.commit();
898+
return true;
899+
}
900+
901+
next_page= false;
902+
block= page_cur_get_block(cur);
903+
block= btr_block_get(page_id_t(block->page.id.space(), next_page_no),
904+
block->page.size, BTR_SEARCH_LEAF, clust_index,
905+
&mtr);
906+
btr_leaf_page_release(page_cur_get_block(cur), BTR_SEARCH_LEAF, &mtr);
907+
page_cur_set_before_first(block, cur);
908+
page_cur_move_to_next(cur);
909+
}
910+
911+
rec= page_cur_get_rec(cur);
912+
if (rec_get_deleted_flag(rec, dict_table_is_comp(table)));
913+
else if (!page_rec_is_supremum(rec))
914+
{
915+
mtr.commit();
916+
return false;
917+
}
918+
else
919+
{
920+
next_page= true;
921+
goto next_page;
922+
}
923+
goto scan_leaf;
924+
}
925+
869926
/** Check if InnoDB supports a particular alter table in-place
870927
@param altered_table TABLE object for new version of table.
871928
@param ha_alter_info Structure describing changes to be done
@@ -1078,6 +1135,13 @@ ha_innobase::check_if_supported_inplace_alter(
10781135
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
10791136
}
10801137

1138+
/* '0000-00-00' value isn't allowed for datetime datatype
1139+
for newly added column when table is not empty */
1140+
if (ha_alter_info->error_if_not_empty
1141+
&& !innobase_table_is_empty(m_prebuilt->table)) {
1142+
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
1143+
}
1144+
10811145
booladd_drop_v_cols = false;
10821146

10831147
/* If there is add or drop virtual columns, we will support operations

0 commit comments

Comments
 (0)