Skip to content
Permalink
Browse files

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.
  • Loading branch information...
dr-m committed Aug 30, 2019
1 parent f42a231 commit 17336f6d3063616443a8f60091fd1f8c694b34f3
@@ -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);
}
}

0 comments on commit 17336f6

Please sign in to comment.
You can’t perform that action at this time.