diff options
-rw-r--r-- | mysql-test/suite/innodb/r/instant_alter.result | 71 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/instant_alter.test | 24 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.cc | 62 |
3 files changed, 123 insertions, 34 deletions
diff --git a/mysql-test/suite/innodb/r/instant_alter.result b/mysql-test/suite/innodb/r/instant_alter.result index 903678348a5..b39e32ce8f4 100644 --- a/mysql-test/suite/innodb/r/instant_alter.result +++ b/mysql-test/suite/innodb/r/instant_alter.result @@ -491,6 +491,29 @@ DELETE FROM t1; COMMIT; InnoDB 0 transactions not purged DROP TABLE t1; +CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB ROW_FORMAT=REDUNDANT; +INSERT INTO t1 VALUES (7); +ALTER TABLE t1 ADD COLUMN c INT NOT NULL DEFAULT 0; +ALTER TABLE t1 ADD INDEX (c); +BEGIN; +DELETE FROM t1; +INSERT INTO t1 VALUES (4,0),(7,77); +COMMIT; +BEGIN; +DELETE FROM t1 WHERE a=7; +UPDATE t1 SET a=7; +COMMIT; +SELECT * FROM t1 FORCE INDEX(PRIMARY); +a c +7 0 +SELECT * FROM t1 FORCE INDEX(c); +a c +7 0 +DELETE FROM t1; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; CREATE TABLE t1 (id INT PRIMARY KEY, c2 INT UNIQUE, c3 POINT NOT NULL DEFAULT ST_GeomFromText('POINT(3 4)'), @@ -927,6 +950,29 @@ DELETE FROM t1; COMMIT; InnoDB 0 transactions not purged DROP TABLE t1; +CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB ROW_FORMAT=COMPACT; +INSERT INTO t1 VALUES (7); +ALTER TABLE t1 ADD COLUMN c INT NOT NULL DEFAULT 0; +ALTER TABLE t1 ADD INDEX (c); +BEGIN; +DELETE FROM t1; +INSERT INTO t1 VALUES (4,0),(7,77); +COMMIT; +BEGIN; +DELETE FROM t1 WHERE a=7; +UPDATE t1 SET a=7; +COMMIT; +SELECT * FROM t1 FORCE INDEX(PRIMARY); +a c +7 0 +SELECT * FROM t1 FORCE INDEX(c); +a c +7 0 +DELETE FROM t1; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; CREATE TABLE t1 (id INT PRIMARY KEY, c2 INT UNIQUE, c3 POINT NOT NULL DEFAULT ST_GeomFromText('POINT(3 4)'), @@ -1363,10 +1409,33 @@ DELETE FROM t1; COMMIT; InnoDB 0 transactions not purged DROP TABLE t1; +CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +INSERT INTO t1 VALUES (7); +ALTER TABLE t1 ADD COLUMN c INT NOT NULL DEFAULT 0; +ALTER TABLE t1 ADD INDEX (c); +BEGIN; +DELETE FROM t1; +INSERT INTO t1 VALUES (4,0),(7,77); +COMMIT; +BEGIN; +DELETE FROM t1 WHERE a=7; +UPDATE t1 SET a=7; +COMMIT; +SELECT * FROM t1 FORCE INDEX(PRIMARY); +a c +7 0 +SELECT * FROM t1 FORCE INDEX(c); +a c +7 0 +DELETE FROM t1; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; disconnect analyze; SELECT variable_value-@old_instant instants FROM information_schema.global_status WHERE variable_name = 'innodb_instant_alter_column'; instants -51 +54 SET GLOBAL innodb_purge_rseg_truncate_frequency= @saved_frequency; diff --git a/mysql-test/suite/innodb/t/instant_alter.test b/mysql-test/suite/innodb/t/instant_alter.test index 58ae6303c00..73f052d3e2b 100644 --- a/mysql-test/suite/innodb/t/instant_alter.test +++ b/mysql-test/suite/innodb/t/instant_alter.test @@ -365,6 +365,30 @@ COMMIT; --source include/wait_all_purged.inc DROP TABLE t1; +# +# MDEV-20066 Wrong value on instantly added column after DELETE and UPDATE +# + +eval CREATE TABLE t1(a INT PRIMARY KEY) $engine; +INSERT INTO t1 VALUES (7); + +ALTER TABLE t1 ADD COLUMN c INT NOT NULL DEFAULT 0; +ALTER TABLE t1 ADD INDEX (c); + +BEGIN; +DELETE FROM t1; +INSERT INTO t1 VALUES (4,0),(7,77); +COMMIT; +BEGIN; +DELETE FROM t1 WHERE a=7; +UPDATE t1 SET a=7; +COMMIT; +SELECT * FROM t1 FORCE INDEX(PRIMARY); +SELECT * FROM t1 FORCE INDEX(c); +DELETE FROM t1; +CHECK TABLE t1; +DROP TABLE t1; + dec $format; } disconnect analyze; diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index c22d422ed86..71494f4f12f 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -1049,22 +1049,21 @@ row_upd_build_difference_binary( TABLE* mysql_table, dberr_t* error) { - upd_field_t* upd_field; ulint len; upd_t* update; ulint n_diff; ulint trx_id_pos; - ulint i; ulint offsets_[REC_OFFS_NORMAL_SIZE]; - ulint n_fld = dtuple_get_n_fields(entry); - ulint n_v_fld = dtuple_get_n_v_fields(entry); + const ulint n_v_fld = dtuple_get_n_v_fields(entry); rec_offs_init(offsets_); /* This function is used only for a clustered index */ ut_a(dict_index_is_clust(index)); ut_ad(!index->table->skip_alter_undo); + ut_ad(entry->n_fields <= index->n_fields); + ut_ad(entry->n_fields >= index->n_core_fields); - update = upd_create(n_fld + n_v_fld, heap); + update = upd_create(index->n_fields + n_v_fld, heap); n_diff = 0; @@ -1079,7 +1078,7 @@ row_upd_build_difference_binary( ut_ad(rec_offs_validate(rec, index, offsets)); } - for (i = 0; i < n_fld; i++) { + for (ulint i = 0; i < entry->n_fields; i++) { const byte* data = rec_get_nth_cfield(rec, index, offsets, i, &len); const dfield_t* dfield = dtuple_get_nth_field(entry, i); @@ -1101,17 +1100,22 @@ row_upd_build_difference_binary( if (!dfield_is_ext(dfield) != !rec_offs_nth_extern(offsets, i) || !dfield_data_is_binary_equal(dfield, len, data)) { - - upd_field = upd_get_nth_field(update, n_diff); - - dfield_copy(&(upd_field->new_val), dfield); - - upd_field_set_field_no(upd_field, i, index); - - n_diff++; + upd_field_t* uf = upd_get_nth_field(update, n_diff++); + dfield_copy(&uf->new_val, dfield); + upd_field_set_field_no(uf, i, index); } } + for (ulint i = entry->n_fields; i < index->n_fields; i++) { + upd_field_t* uf = upd_get_nth_field(update, n_diff++); + const dict_col_t* col = dict_index_get_nth_col(index, i); + /* upd_create() zero-initialized uf */ + uf->new_val.data = const_cast<byte*>(col->instant_value(&len)); + uf->new_val.len = static_cast<unsigned>(len); + dict_col_copy_type(col, &uf->new_val.type); + upd_field_set_field_no(uf, i, index); + } + /* Check the virtual columns updates. Even if there is no non-virtual column (base columns) change, we will still need to build the indexed virtual column value so that undo log would log them ( @@ -1136,7 +1140,7 @@ row_upd_build_difference_binary( &mysql_table, &record, &vcol_storage); - for (i = 0; i < n_v_fld; i++) { + for (ulint i = 0; i < n_v_fld; i++) { const dict_v_col_t* col = dict_table_get_nth_v_col(index->table, i); @@ -1164,24 +1168,16 @@ row_upd_build_difference_binary( entry, i); if (!dfield_data_is_binary_equal( - dfield, vfield->len, - static_cast<byte*>(vfield->data))) { - upd_field = upd_get_nth_field(update, n_diff); - - upd_field->old_v_val = static_cast<dfield_t*>( - mem_heap_alloc( - heap, - sizeof *upd_field->old_v_val)); - - dfield_copy(upd_field->old_v_val, vfield); - - dfield_copy(&(upd_field->new_val), dfield); - - upd_field_set_v_field_no( - upd_field, i, index); - - n_diff++; - + dfield, vfield->len, + static_cast<byte*>(vfield->data))) { + upd_field_t* uf = upd_get_nth_field(update, + n_diff++); + uf->old_v_val = static_cast<dfield_t*>( + mem_heap_alloc(heap, + sizeof *uf->old_v_val)); + dfield_copy(uf->old_v_val, vfield); + dfield_copy(&uf->new_val, dfield); + upd_field_set_v_field_no(uf, i, index); } } |