Skip to content

Commit 17336f6

Browse files
committed
MDEV-20066 Wrong value on instantly added column after DELETE and UPDATE
row_upd_build_difference_binary(): Correctly handle the case where columns (or clustered index fields) have been added since the 'entry' was originally created. In this case, the update vector must replace any missing columns with the default values of the instantly added columns.
1 parent f42a231 commit 17336f6

File tree

3 files changed

+123
-34
lines changed

3 files changed

+123
-34
lines changed

mysql-test/suite/innodb/r/instant_alter.result

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,29 @@ DELETE FROM t1;
491491
COMMIT;
492492
InnoDB 0 transactions not purged
493493
DROP TABLE t1;
494+
CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
495+
INSERT INTO t1 VALUES (7);
496+
ALTER TABLE t1 ADD COLUMN c INT NOT NULL DEFAULT 0;
497+
ALTER TABLE t1 ADD INDEX (c);
498+
BEGIN;
499+
DELETE FROM t1;
500+
INSERT INTO t1 VALUES (4,0),(7,77);
501+
COMMIT;
502+
BEGIN;
503+
DELETE FROM t1 WHERE a=7;
504+
UPDATE t1 SET a=7;
505+
COMMIT;
506+
SELECT * FROM t1 FORCE INDEX(PRIMARY);
507+
a c
508+
7 0
509+
SELECT * FROM t1 FORCE INDEX(c);
510+
a c
511+
7 0
512+
DELETE FROM t1;
513+
CHECK TABLE t1;
514+
Table Op Msg_type Msg_text
515+
test.t1 check status OK
516+
DROP TABLE t1;
494517
CREATE TABLE t1
495518
(id INT PRIMARY KEY, c2 INT UNIQUE,
496519
c3 POINT NOT NULL DEFAULT ST_GeomFromText('POINT(3 4)'),
@@ -927,6 +950,29 @@ DELETE FROM t1;
927950
COMMIT;
928951
InnoDB 0 transactions not purged
929952
DROP TABLE t1;
953+
CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB ROW_FORMAT=COMPACT;
954+
INSERT INTO t1 VALUES (7);
955+
ALTER TABLE t1 ADD COLUMN c INT NOT NULL DEFAULT 0;
956+
ALTER TABLE t1 ADD INDEX (c);
957+
BEGIN;
958+
DELETE FROM t1;
959+
INSERT INTO t1 VALUES (4,0),(7,77);
960+
COMMIT;
961+
BEGIN;
962+
DELETE FROM t1 WHERE a=7;
963+
UPDATE t1 SET a=7;
964+
COMMIT;
965+
SELECT * FROM t1 FORCE INDEX(PRIMARY);
966+
a c
967+
7 0
968+
SELECT * FROM t1 FORCE INDEX(c);
969+
a c
970+
7 0
971+
DELETE FROM t1;
972+
CHECK TABLE t1;
973+
Table Op Msg_type Msg_text
974+
test.t1 check status OK
975+
DROP TABLE t1;
930976
CREATE TABLE t1
931977
(id INT PRIMARY KEY, c2 INT UNIQUE,
932978
c3 POINT NOT NULL DEFAULT ST_GeomFromText('POINT(3 4)'),
@@ -1363,10 +1409,33 @@ DELETE FROM t1;
13631409
COMMIT;
13641410
InnoDB 0 transactions not purged
13651411
DROP TABLE t1;
1412+
CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
1413+
INSERT INTO t1 VALUES (7);
1414+
ALTER TABLE t1 ADD COLUMN c INT NOT NULL DEFAULT 0;
1415+
ALTER TABLE t1 ADD INDEX (c);
1416+
BEGIN;
1417+
DELETE FROM t1;
1418+
INSERT INTO t1 VALUES (4,0),(7,77);
1419+
COMMIT;
1420+
BEGIN;
1421+
DELETE FROM t1 WHERE a=7;
1422+
UPDATE t1 SET a=7;
1423+
COMMIT;
1424+
SELECT * FROM t1 FORCE INDEX(PRIMARY);
1425+
a c
1426+
7 0
1427+
SELECT * FROM t1 FORCE INDEX(c);
1428+
a c
1429+
7 0
1430+
DELETE FROM t1;
1431+
CHECK TABLE t1;
1432+
Table Op Msg_type Msg_text
1433+
test.t1 check status OK
1434+
DROP TABLE t1;
13661435
disconnect analyze;
13671436
SELECT variable_value-@old_instant instants
13681437
FROM information_schema.global_status
13691438
WHERE variable_name = 'innodb_instant_alter_column';
13701439
instants
1371-
51
1440+
54
13721441
SET GLOBAL innodb_purge_rseg_truncate_frequency= @saved_frequency;

mysql-test/suite/innodb/t/instant_alter.test

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,30 @@ COMMIT;
365365
--source include/wait_all_purged.inc
366366
DROP TABLE t1;
367367

368+
#
369+
# MDEV-20066 Wrong value on instantly added column after DELETE and UPDATE
370+
#
371+
372+
eval CREATE TABLE t1(a INT PRIMARY KEY) $engine;
373+
INSERT INTO t1 VALUES (7);
374+
375+
ALTER TABLE t1 ADD COLUMN c INT NOT NULL DEFAULT 0;
376+
ALTER TABLE t1 ADD INDEX (c);
377+
378+
BEGIN;
379+
DELETE FROM t1;
380+
INSERT INTO t1 VALUES (4,0),(7,77);
381+
COMMIT;
382+
BEGIN;
383+
DELETE FROM t1 WHERE a=7;
384+
UPDATE t1 SET a=7;
385+
COMMIT;
386+
SELECT * FROM t1 FORCE INDEX(PRIMARY);
387+
SELECT * FROM t1 FORCE INDEX(c);
388+
DELETE FROM t1;
389+
CHECK TABLE t1;
390+
DROP TABLE t1;
391+
368392
dec $format;
369393
}
370394
disconnect analyze;

storage/innobase/row/row0upd.cc

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,22 +1049,21 @@ row_upd_build_difference_binary(
10491049
TABLE* mysql_table,
10501050
dberr_t* error)
10511051
{
1052-
upd_field_t* upd_field;
10531052
ulint len;
10541053
upd_t* update;
10551054
ulint n_diff;
10561055
ulint trx_id_pos;
1057-
ulint i;
10581056
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1059-
ulint n_fld = dtuple_get_n_fields(entry);
1060-
ulint n_v_fld = dtuple_get_n_v_fields(entry);
1057+
const ulint n_v_fld = dtuple_get_n_v_fields(entry);
10611058
rec_offs_init(offsets_);
10621059

10631060
/* This function is used only for a clustered index */
10641061
ut_a(dict_index_is_clust(index));
10651062
ut_ad(!index->table->skip_alter_undo);
1063+
ut_ad(entry->n_fields <= index->n_fields);
1064+
ut_ad(entry->n_fields >= index->n_core_fields);
10661065

1067-
update = upd_create(n_fld + n_v_fld, heap);
1066+
update = upd_create(index->n_fields + n_v_fld, heap);
10681067

10691068
n_diff = 0;
10701069

@@ -1079,7 +1078,7 @@ row_upd_build_difference_binary(
10791078
ut_ad(rec_offs_validate(rec, index, offsets));
10801079
}
10811080

1082-
for (i = 0; i < n_fld; i++) {
1081+
for (ulint i = 0; i < entry->n_fields; i++) {
10831082
const byte* data = rec_get_nth_cfield(rec, index, offsets, i,
10841083
&len);
10851084
const dfield_t* dfield = dtuple_get_nth_field(entry, i);
@@ -1101,17 +1100,22 @@ row_upd_build_difference_binary(
11011100
if (!dfield_is_ext(dfield)
11021101
!= !rec_offs_nth_extern(offsets, i)
11031102
|| !dfield_data_is_binary_equal(dfield, len, data)) {
1104-
1105-
upd_field = upd_get_nth_field(update, n_diff);
1106-
1107-
dfield_copy(&(upd_field->new_val), dfield);
1108-
1109-
upd_field_set_field_no(upd_field, i, index);
1110-
1111-
n_diff++;
1103+
upd_field_t* uf = upd_get_nth_field(update, n_diff++);
1104+
dfield_copy(&uf->new_val, dfield);
1105+
upd_field_set_field_no(uf, i, index);
11121106
}
11131107
}
11141108

1109+
for (ulint i = entry->n_fields; i < index->n_fields; i++) {
1110+
upd_field_t* uf = upd_get_nth_field(update, n_diff++);
1111+
const dict_col_t* col = dict_index_get_nth_col(index, i);
1112+
/* upd_create() zero-initialized uf */
1113+
uf->new_val.data = const_cast<byte*>(col->instant_value(&len));
1114+
uf->new_val.len = static_cast<unsigned>(len);
1115+
dict_col_copy_type(col, &uf->new_val.type);
1116+
upd_field_set_field_no(uf, i, index);
1117+
}
1118+
11151119
/* Check the virtual columns updates. Even if there is no non-virtual
11161120
column (base columns) change, we will still need to build the
11171121
indexed virtual column value so that undo log would log them (
@@ -1136,7 +1140,7 @@ row_upd_build_difference_binary(
11361140
&mysql_table,
11371141
&record, &vcol_storage);
11381142

1139-
for (i = 0; i < n_v_fld; i++) {
1143+
for (ulint i = 0; i < n_v_fld; i++) {
11401144
const dict_v_col_t* col
11411145
= dict_table_get_nth_v_col(index->table, i);
11421146

@@ -1164,24 +1168,16 @@ row_upd_build_difference_binary(
11641168
entry, i);
11651169

11661170
if (!dfield_data_is_binary_equal(
1167-
dfield, vfield->len,
1168-
static_cast<byte*>(vfield->data))) {
1169-
upd_field = upd_get_nth_field(update, n_diff);
1170-
1171-
upd_field->old_v_val = static_cast<dfield_t*>(
1172-
mem_heap_alloc(
1173-
heap,
1174-
sizeof *upd_field->old_v_val));
1175-
1176-
dfield_copy(upd_field->old_v_val, vfield);
1177-
1178-
dfield_copy(&(upd_field->new_val), dfield);
1179-
1180-
upd_field_set_v_field_no(
1181-
upd_field, i, index);
1182-
1183-
n_diff++;
1184-
1171+
dfield, vfield->len,
1172+
static_cast<byte*>(vfield->data))) {
1173+
upd_field_t* uf = upd_get_nth_field(update,
1174+
n_diff++);
1175+
uf->old_v_val = static_cast<dfield_t*>(
1176+
mem_heap_alloc(heap,
1177+
sizeof *uf->old_v_val));
1178+
dfield_copy(uf->old_v_val, vfield);
1179+
dfield_copy(&uf->new_val, dfield);
1180+
upd_field_set_v_field_no(uf, i, index);
11851181
}
11861182
}
11871183

0 commit comments

Comments
 (0)