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

MDEV-17901 Crash after instant DROP COLUMN of AUTO_INCREMENT column

We failed to reset the dict_table_t::persistent_autoinc after
instantly dropping an AUTO_INCREMENT column, causing a bogus
call to row_parse_int() on a subsequent insert.
parent 8dc460b8
...@@ -565,6 +565,19 @@ ALTER TABLE t1 DROP f2, ADD COLUMN f4 INT; ...@@ -565,6 +565,19 @@ ALTER TABLE t1 DROP f2, ADD COLUMN f4 INT;
ALTER TABLE t1 DROP f4; ALTER TABLE t1 DROP f4;
ALTER TABLE t1 DROP f1; ALTER TABLE t1 DROP f1;
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (id INT NOT NULL AUTO_INCREMENT, f INT, KEY(id)) ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
ALTER TABLE t1 DROP COLUMN id;
INSERT INTO t1 () VALUES (),();
SELECT * FROM t1;
f
NULL
NULL
ALTER TABLE t1 ADD COLUMN id INT NOT NULL AUTO_INCREMENT FIRST, ADD KEY(id);
SELECT * FROM t1;
id f
1 NULL
2 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)'),
...@@ -1076,6 +1089,19 @@ ALTER TABLE t1 DROP f2, ADD COLUMN f4 INT; ...@@ -1076,6 +1089,19 @@ ALTER TABLE t1 DROP f2, ADD COLUMN f4 INT;
ALTER TABLE t1 DROP f4; ALTER TABLE t1 DROP f4;
ALTER TABLE t1 DROP f1; ALTER TABLE t1 DROP f1;
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (id INT NOT NULL AUTO_INCREMENT, f INT, KEY(id)) ENGINE=InnoDB ROW_FORMAT=COMPACT;
ALTER TABLE t1 DROP COLUMN id;
INSERT INTO t1 () VALUES (),();
SELECT * FROM t1;
f
NULL
NULL
ALTER TABLE t1 ADD COLUMN id INT NOT NULL AUTO_INCREMENT FIRST, ADD KEY(id);
SELECT * FROM t1;
id f
1 NULL
2 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)'),
...@@ -1587,10 +1613,23 @@ ALTER TABLE t1 DROP f2, ADD COLUMN f4 INT; ...@@ -1587,10 +1613,23 @@ ALTER TABLE t1 DROP f2, ADD COLUMN f4 INT;
ALTER TABLE t1 DROP f4; ALTER TABLE t1 DROP f4;
ALTER TABLE t1 DROP f1; ALTER TABLE t1 DROP f1;
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (id INT NOT NULL AUTO_INCREMENT, f INT, KEY(id)) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
ALTER TABLE t1 DROP COLUMN id;
INSERT INTO t1 () VALUES (),();
SELECT * FROM t1;
f
NULL
NULL
ALTER TABLE t1 ADD COLUMN id INT NOT NULL AUTO_INCREMENT FIRST, ADD KEY(id);
SELECT * FROM t1;
id f
1 NULL
2 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
111 114
SET GLOBAL innodb_purge_rseg_truncate_frequency= @saved_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency= @saved_frequency;
...@@ -437,6 +437,16 @@ ALTER TABLE t1 DROP f4; ...@@ -437,6 +437,16 @@ ALTER TABLE t1 DROP f4;
ALTER TABLE t1 DROP f1; ALTER TABLE t1 DROP f1;
DROP TABLE t1; DROP TABLE t1;
# MDEV-17901 Crash after instant DROP COLUMN of AUTO_INCREMENT column
eval CREATE TABLE t1 (id INT NOT NULL AUTO_INCREMENT, f INT, KEY(id)) $engine;
ALTER TABLE t1 DROP COLUMN id;
INSERT INTO t1 () VALUES (),();
SELECT * FROM t1;
# Adding AUTO_INCREMENT column will always require rebuild.
ALTER TABLE t1 ADD COLUMN id INT NOT NULL AUTO_INCREMENT FIRST, ADD KEY(id);
SELECT * FROM t1;
DROP TABLE t1;
dec $format; dec $format;
} }
disconnect analyze; disconnect analyze;
......
...@@ -173,6 +173,8 @@ inline void dict_table_t::prepare_instant(const dict_table_t& old, ...@@ -173,6 +173,8 @@ inline void dict_table_t::prepare_instant(const dict_table_t& old,
DBUG_ASSERT(old.n_cols == old.n_def); DBUG_ASSERT(old.n_cols == old.n_def);
DBUG_ASSERT(n_cols == n_def); DBUG_ASSERT(n_cols == n_def);
DBUG_ASSERT(old.supports_instant()); DBUG_ASSERT(old.supports_instant());
DBUG_ASSERT(!persistent_autoinc
|| persistent_autoinc == old.persistent_autoinc);
/* supports_instant() does not necessarily hold here, /* supports_instant() does not necessarily hold here,
in case ROW_FORMAT=COMPRESSED according to the in case ROW_FORMAT=COMPRESSED according to the
MariaDB data dictionary, and ALTER_OPTIONS was not set. MariaDB data dictionary, and ALTER_OPTIONS was not set.
...@@ -431,6 +433,8 @@ inline void dict_table_t::instant_column(const dict_table_t& table, ...@@ -431,6 +433,8 @@ inline void dict_table_t::instant_column(const dict_table_t& table,
DBUG_ASSERT(n_v_def == n_v_cols); DBUG_ASSERT(n_v_def == n_v_cols);
DBUG_ASSERT(table.n_v_def == table.n_v_cols); DBUG_ASSERT(table.n_v_def == table.n_v_cols);
DBUG_ASSERT(table.n_cols + table.n_dropped() >= n_cols + n_dropped()); DBUG_ASSERT(table.n_cols + table.n_dropped() >= n_cols + n_dropped());
DBUG_ASSERT(!table.persistent_autoinc
|| persistent_autoinc == table.persistent_autoinc);
ut_ad(mutex_own(&dict_sys->mutex)); ut_ad(mutex_own(&dict_sys->mutex));
{ {
...@@ -6202,6 +6206,9 @@ prepare_inplace_alter_table_dict( ...@@ -6202,6 +6206,9 @@ prepare_inplace_alter_table_dict(
== !!new_clustered); == !!new_clustered);
} }
DBUG_ASSERT(!ctx->need_rebuild()
|| !ctx->new_table->persistent_autoinc);
if (ctx->need_rebuild() && instant_alter_column_possible( if (ctx->need_rebuild() && instant_alter_column_possible(
*user_table, ha_alter_info, old_table) *user_table, ha_alter_info, old_table)
#if 1 // MDEV-17459: adjust fts_fetch_doc_from_rec() and friends; remove this #if 1 // MDEV-17459: adjust fts_fetch_doc_from_rec() and friends; remove this
...@@ -6330,6 +6337,11 @@ prepare_inplace_alter_table_dict( ...@@ -6330,6 +6337,11 @@ prepare_inplace_alter_table_dict(
ctx->new_table, i), ctx->new_table, i),
FTS_DOC_ID_COL_NAME))); FTS_DOC_ID_COL_NAME)));
if (altered_table->found_next_number_field) {
ctx->new_table->persistent_autoinc
= ctx->old_table->persistent_autoinc;
}
ctx->prepare_instant(); ctx->prepare_instant();
} }
...@@ -6462,7 +6474,6 @@ prepare_inplace_alter_table_dict( ...@@ -6462,7 +6474,6 @@ prepare_inplace_alter_table_dict(
ut_ad(new_clust_index->n_core_null_bytes ut_ad(new_clust_index->n_core_null_bytes
== UT_BITS_IN_BYTES(new_clust_index->n_nullable)); == UT_BITS_IN_BYTES(new_clust_index->n_nullable));
DBUG_ASSERT(!ctx->new_table->persistent_autoinc);
if (const Field* ai = altered_table->found_next_number_field) { if (const Field* ai = altered_table->found_next_number_field) {
const unsigned col_no = innodb_col_no(ai); const unsigned col_no = innodb_col_no(ai);
...@@ -10142,8 +10153,8 @@ commit_cache_norebuild( ...@@ -10142,8 +10153,8 @@ commit_cache_norebuild(
} }
if (ha_alter_info->handler_flags & ALTER_DROP_STORED_COLUMN) { if (ha_alter_info->handler_flags & ALTER_DROP_STORED_COLUMN) {
dict_index_t* index = dict_table_get_first_index( const dict_index_t* index = ctx->new_table->indexes.start;
ctx->new_table);
for (const dict_field_t* f = index->fields, for (const dict_field_t* f = index->fields,
* const end = f + index->n_fields; * const end = f + index->n_fields;
f != end; f++) { f != end; f++) {
...@@ -10156,6 +10167,14 @@ commit_cache_norebuild( ...@@ -10156,6 +10167,14 @@ commit_cache_norebuild(
f->fixed_len); f->fixed_len);
} }
} }
DBUG_ASSERT(!ctx->instant_table->persistent_autoinc
|| ctx->new_table->persistent_autoinc
== ctx->instant_table->persistent_autoinc);
if (!ctx->instant_table->persistent_autoinc) {
ctx->new_table->persistent_autoinc = 0;
}
} }
} }
......
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