Commit 17336f6d authored by Marko Mäkelä's avatar Marko Mäkelä

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.
parent f42a2317
......@@ -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;
......@@ -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;
......
......@@ -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);
}
}
......
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