Commit 00372075 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-18033/MDEV-18034: Assertion failed on NOT NULL removal

innobase_instant_try(): Only try to update the hidden metadata
record if the number of columns is changing (increasing) or
a metadata BLOB is being added due to permuting or dropping columns
for the first time.

dict_table_t::instant_column(), ha_innobase_inplace_ctx::instant_column():
Return whether the metadata record needs to be updated.
parent 3b5e8d79
...@@ -624,6 +624,11 @@ CREATE TABLE t1 (a INT, b INT, c INT NOT NULL, d INT, ...@@ -624,6 +624,11 @@ CREATE TABLE t1 (a INT, b INT, c INT NOT NULL, d INT,
e INT, f INT, g INT, h INT, j INT) ENGINE=InnoDB ROW_FORMAT=REDUNDANT; e INT, f INT, g INT, h INT, j INT) ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
ALTER TABLE t1 MODIFY COLUMN c INT, MODIFY COLUMN a INT AFTER b; ALTER TABLE t1 MODIFY COLUMN c INT, MODIFY COLUMN a INT AFTER b;
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (a INT NOT NULL) ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
INSERT INTO t1 VALUES (1);
ALTER TABLE t1 ADD COLUMN b INT;
ALTER TABLE t1 MODIFY COLUMN a INT NULL;
DROP TABLE t1;
CREATE TABLE t1 CREATE TABLE t1
(id INT PRIMARY KEY, c2 INT UNIQUE, (id INT PRIMARY KEY, c2 INT UNIQUE,
c3 POINT NOT NULL DEFAULT ST_GeomFromText('POINT(3 4)'), c3 POINT NOT NULL DEFAULT ST_GeomFromText('POINT(3 4)'),
...@@ -1194,6 +1199,11 @@ CREATE TABLE t1 (a INT, b INT, c INT NOT NULL, d INT, ...@@ -1194,6 +1199,11 @@ CREATE TABLE t1 (a INT, b INT, c INT NOT NULL, d INT,
e INT, f INT, g INT, h INT, j INT) ENGINE=InnoDB ROW_FORMAT=COMPACT; e INT, f INT, g INT, h INT, j INT) ENGINE=InnoDB ROW_FORMAT=COMPACT;
ALTER TABLE t1 MODIFY COLUMN c INT, MODIFY COLUMN a INT AFTER b; ALTER TABLE t1 MODIFY COLUMN c INT, MODIFY COLUMN a INT AFTER b;
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (a INT NOT NULL) ENGINE=InnoDB ROW_FORMAT=COMPACT;
INSERT INTO t1 VALUES (1);
ALTER TABLE t1 ADD COLUMN b INT;
ALTER TABLE t1 MODIFY COLUMN a INT NULL;
DROP TABLE t1;
CREATE TABLE t1 CREATE TABLE t1
(id INT PRIMARY KEY, c2 INT UNIQUE, (id INT PRIMARY KEY, c2 INT UNIQUE,
c3 POINT NOT NULL DEFAULT ST_GeomFromText('POINT(3 4)'), c3 POINT NOT NULL DEFAULT ST_GeomFromText('POINT(3 4)'),
...@@ -1764,10 +1774,15 @@ CREATE TABLE t1 (a INT, b INT, c INT NOT NULL, d INT, ...@@ -1764,10 +1774,15 @@ CREATE TABLE t1 (a INT, b INT, c INT NOT NULL, d INT,
e INT, f INT, g INT, h INT, j INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; e INT, f INT, g INT, h INT, j INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
ALTER TABLE t1 MODIFY COLUMN c INT, MODIFY COLUMN a INT AFTER b; ALTER TABLE t1 MODIFY COLUMN c INT, MODIFY COLUMN a INT AFTER b;
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (a INT NOT NULL) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
INSERT INTO t1 VALUES (1);
ALTER TABLE t1 ADD COLUMN b INT;
ALTER TABLE t1 MODIFY COLUMN a INT NULL;
DROP TABLE t1;
disconnect analyze; disconnect analyze;
SELECT variable_value-@old_instant instants SELECT variable_value-@old_instant instants
FROM information_schema.global_status FROM information_schema.global_status
WHERE variable_name = 'innodb_instant_alter_column'; WHERE variable_name = 'innodb_instant_alter_column';
instants instants
121 125
SET GLOBAL innodb_purge_rseg_truncate_frequency= @saved_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency= @saved_frequency;
...@@ -503,6 +503,13 @@ e INT, f INT, g INT, h INT, j INT) $engine; ...@@ -503,6 +503,13 @@ e INT, f INT, g INT, h INT, j INT) $engine;
ALTER TABLE t1 MODIFY COLUMN c INT, MODIFY COLUMN a INT AFTER b; ALTER TABLE t1 MODIFY COLUMN c INT, MODIFY COLUMN a INT AFTER b;
DROP TABLE t1; DROP TABLE t1;
# MDEV-18033/MDEV-18034 Failing assertion on ALTER
eval CREATE TABLE t1 (a INT NOT NULL) $engine;
INSERT INTO t1 VALUES (1);
ALTER TABLE t1 ADD COLUMN b INT;
ALTER TABLE t1 MODIFY COLUMN a INT NULL;
DROP TABLE t1;
dec $format; dec $format;
} }
disconnect analyze; disconnect analyze;
......
...@@ -497,8 +497,9 @@ inline void dict_index_t::instant_add_field(const dict_index_t& instant) ...@@ -497,8 +497,9 @@ inline void dict_index_t::instant_add_field(const dict_index_t& instant)
/** Adjust table metadata for instant ADD/DROP/reorder COLUMN. /** Adjust table metadata for instant ADD/DROP/reorder COLUMN.
@param[in] table altered table (with dropped columns) @param[in] table altered table (with dropped columns)
@param[in] col_map mapping from cols[] and v_cols[] to table */ @param[in] col_map mapping from cols[] and v_cols[] to table
inline void dict_table_t::instant_column(const dict_table_t& table, @return whether the metadata record must be updated */
inline bool dict_table_t::instant_column(const dict_table_t& table,
const ulint* col_map) const ulint* col_map)
{ {
DBUG_ASSERT(!table.cached); DBUG_ASSERT(!table.cached);
...@@ -608,10 +609,16 @@ inline void dict_table_t::instant_column(const dict_table_t& table, ...@@ -608,10 +609,16 @@ inline void dict_table_t::instant_column(const dict_table_t& table,
} }
dict_index_t* index = dict_table_get_first_index(this); dict_index_t* index = dict_table_get_first_index(this);
bool metadata_changed;
index->instant_add_field(*dict_table_get_first_index(&table)); {
const dict_index_t& i = *dict_table_get_first_index(&table);
metadata_changed = i.n_fields > index->n_fields;
ut_ad(i.n_fields >= index->n_fields);
index->instant_add_field(i);
}
if (instant || table.instant) { if (instant || table.instant) {
const auto old_instant = instant;
/* FIXME: add instant->heap, and transfer ownership here */ /* FIXME: add instant->heap, and transfer ownership here */
if (!instant) { if (!instant) {
instant = new (mem_heap_zalloc(heap, sizeof *instant)) instant = new (mem_heap_zalloc(heap, sizeof *instant))
...@@ -631,6 +638,15 @@ inline void dict_table_t::instant_column(const dict_table_t& table, ...@@ -631,6 +638,15 @@ inline void dict_table_t::instant_column(const dict_table_t& table,
} }
init_instant<true>(table); init_instant<true>(table);
if (!metadata_changed) {
metadata_changed = !old_instant
|| memcmp(old_instant->field_map,
instant->field_map,
(index->n_fields
- index->first_user_field())
* sizeof *old_instant->field_map);
}
} }
while ((index = dict_table_get_next_index(index)) != NULL) { while ((index = dict_table_get_next_index(index)) != NULL) {
...@@ -678,6 +694,7 @@ inline void dict_table_t::instant_column(const dict_table_t& table, ...@@ -678,6 +694,7 @@ inline void dict_table_t::instant_column(const dict_table_t& table,
n_cols = table.n_cols; n_cols = table.n_cols;
n_v_cols = table.n_v_cols; n_v_cols = table.n_v_cols;
return metadata_changed;
} }
/** Find the old column number for the given new column position. /** Find the old column number for the given new column position.
...@@ -1024,13 +1041,14 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx ...@@ -1024,13 +1041,14 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
first_alter_pos); first_alter_pos);
} }
/** Adjust table metadata for instant ADD/DROP/reorder COLUMN. */ /** Adjust table metadata for instant ADD/DROP/reorder COLUMN.
void instant_column() @return whether the metadata record must be updated */
bool instant_column()
{ {
DBUG_ASSERT(is_instant()); DBUG_ASSERT(is_instant());
DBUG_ASSERT(old_n_fields DBUG_ASSERT(old_n_fields
== old_table->indexes.start->n_fields); == old_table->indexes.start->n_fields);
old_table->instant_column(*instant_table, col_map); return old_table->instant_column(*instant_table, col_map);
} }
/** Revert prepare_instant() if the transaction is rolled back. */ /** Revert prepare_instant() if the transaction is rolled back. */
...@@ -5413,7 +5431,7 @@ static bool innobase_instant_try( ...@@ -5413,7 +5431,7 @@ static bool innobase_instant_try(
const dict_col_t* old_cols = user_table->cols; const dict_col_t* old_cols = user_table->cols;
DBUG_ASSERT(user_table->n_cols == ctx->old_n_cols); DBUG_ASSERT(user_table->n_cols == ctx->old_n_cols);
ctx->instant_column(); const bool metadata_changed = ctx->instant_column();
DBUG_ASSERT(index->n_fields >= n_old_fields); DBUG_ASSERT(index->n_fields >= n_old_fields);
/* Release the page latch. Between this and the next /* Release the page latch. Between this and the next
...@@ -5598,6 +5616,10 @@ static bool innobase_instant_try( ...@@ -5598,6 +5616,10 @@ static bool innobase_instant_try(
goto empty_table; goto empty_table;
} }
if (!metadata_changed) {
goto func_exit;
}
/* Ensure that the root page is in the correct format. */ /* Ensure that the root page is in the correct format. */
buf_block_t* root = btr_root_block_get(index, RW_X_LATCH, buf_block_t* root = btr_root_block_get(index, RW_X_LATCH,
&mtr); &mtr);
......
...@@ -1710,8 +1710,9 @@ struct dict_table_t { ...@@ -1710,8 +1710,9 @@ struct dict_table_t {
/** Adjust table metadata for instant ADD/DROP/reorder COLUMN. /** Adjust table metadata for instant ADD/DROP/reorder COLUMN.
@param[in] table table on which prepare_instant() was invoked @param[in] table table on which prepare_instant() was invoked
@param[in] col_map mapping from cols[] and v_cols[] to table */ @param[in] col_map mapping from cols[] and v_cols[] to table
inline void instant_column(const dict_table_t& table, @return whether the metadata record must be updated */
inline bool instant_column(const dict_table_t& table,
const ulint* col_map); const ulint* col_map);
/** Roll back instant_column(). /** Roll back instant_column().
......
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