summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/innodb/r/instant_alter.result71
-rw-r--r--mysql-test/suite/innodb/t/instant_alter.test24
-rw-r--r--storage/innobase/row/row0upd.cc62
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);
}
}