mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
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
This commit is contained in:
@ -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;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
--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;
|
|||||||
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 @@ public:
|
|||||||
*/
|
*/
|
||||||
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 @@ public:
|
|||||||
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:;
|
|||||||
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 @@ err_new_table_cleanup:
|
|||||||
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(
|
|||||||
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(
|
|||||||
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
|
||||||
|
Reference in New Issue
Block a user