Skip to content
/ server Public

Commit ccee665

Browse files
committed
MDEV-38734: Virtual columns wrongly included in binlog_row_image=MINIMAL
The original symptom of this was an assertion 'marked_for_read()' failing in RBR with unique blobs and binlog_row_image=MINIMAL. The problem was that the hidden DB_ROW_HASH_1 virtual column was included in the after-image of the update, but the underlying blob column was not being updated, so it was not in the read_set/write_set. It seems clearly wrong to include the DB_ROW_HASH_1 in the after-image when the underlying blob isn't even being updated. The cause of this is the following commit: Author: Monty <[email protected]> Date: Wed May 23 22:42:29 2018 +0300 MDEV-15243 Crash with virtual fields and row based binary logging That patch removed a check for if the underlying fields of a virtual column were being updated, and just added them unconditionally. This seems wrong. So revert that part of the commit, restoring the logic to only add a virtual column if any underlying field is actually in the write_set. Also fix a typo in that commit where a code reformat accidentally reversed a condition. Also fix an assertion when InnoDB goes to update secondary indexes: If any part of the primary key is being updated, then add all virtual columns that are part of secondary indexes to the read_set. Signed-off-by: Kristian Nielsen <[email protected]>
1 parent ec58c02 commit ccee665

File tree

4 files changed

+84
-8
lines changed

4 files changed

+84
-8
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
include/master-slave.inc
2+
[connection master]
3+
connection slave;
4+
SET @row_image_save = @@global.binlog_row_image;
5+
SET GLOBAL binlog_row_image=MINIMAL;
6+
include/stop_slave.inc
7+
include/start_slave.inc
8+
connection master;
9+
SET binlog_row_image=MINIMAL;
10+
CREATE TABLE t (pk int primary key, a text, b text, unique(b));
11+
INSERT INTO t VALUES (1,'foo', 'bar');
12+
UPDATE t SET a = 'baz';
13+
connection slave;
14+
SET GLOBAL binlog_row_image = @row_image_save;
15+
connection master;
16+
DROP TABLE t;
17+
include/rpl_end.inc
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--source include/have_binlog_format_row.inc
2+
--source include/master-slave.inc
3+
4+
--connection slave
5+
SET @row_image_save = @@global.binlog_row_image;
6+
SET GLOBAL binlog_row_image=MINIMAL;
7+
--source include/stop_slave.inc
8+
--source include/start_slave.inc
9+
10+
--connection master
11+
SET binlog_row_image=MINIMAL;
12+
CREATE TABLE t (pk int primary key, a text, b text, unique(b));
13+
INSERT INTO t VALUES (1,'foo', 'bar');
14+
UPDATE t SET a = 'baz';
15+
16+
--sync_slave_with_master
17+
SET GLOBAL binlog_row_image = @row_image_save;
18+
19+
--connection master
20+
DROP TABLE t;
21+
--source include/rpl_end.inc

sql/table.cc

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8186,8 +8186,7 @@ void TABLE::mark_columns_per_binlog_row_image()
81868186
be added to read_set either.
81878187
*/
81888188

8189-
bool TABLE::mark_virtual_columns_for_write(bool insert_fl
8190-
__attribute__((unused)))
8189+
bool TABLE::mark_virtual_columns_for_write(bool insert_fl)
81918190
{
81928191
Field **vfield_ptr, *tmp_vfield;
81938192
bool bitmap_updated= false;
@@ -8202,9 +8201,29 @@ bool TABLE::mark_virtual_columns_for_write(bool insert_fl
82028201
(tmp_vfield->flags & (PART_KEY_FLAG | FIELD_IN_PART_FUNC_FLAG |
82038202
PART_INDIRECT_KEY_FLAG)))
82048203
{
8205-
bitmap_set_bit(write_set, tmp_vfield->field_index);
8206-
mark_virtual_column_with_deps(tmp_vfield);
8207-
bitmap_updated= true;
8204+
if (insert_fl)
8205+
{
8206+
bitmap_set_bit(write_set, tmp_vfield->field_index);
8207+
mark_virtual_column_with_deps(tmp_vfield);
8208+
bitmap_updated= true;
8209+
}
8210+
else
8211+
{
8212+
MY_BITMAP *save_read_set= read_set;
8213+
Item *vcol_item= tmp_vfield->vcol_info->expr;
8214+
DBUG_ASSERT(vcol_item);
8215+
bitmap_clear_all(&tmp_set);
8216+
read_set= &tmp_set;
8217+
vcol_item->walk(&Item::register_field_in_read_map, 1, 0);
8218+
read_set= save_read_set;
8219+
if (bitmap_is_overlapping(&tmp_set, write_set))
8220+
{
8221+
bitmap_set_bit(write_set, tmp_vfield->field_index);
8222+
bitmap_set_bit(read_set, tmp_vfield->field_index);
8223+
bitmap_union(read_set, &tmp_set);
8224+
bitmap_updated= true;
8225+
}
8226+
}
82088227
}
82098228
}
82108229
if (bitmap_updated)
@@ -9267,7 +9286,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
92679286
/* Read indexed fields that was not updated in VCOL_UPDATE_FOR_READ */
92689287
update= (!vcol_info->is_stored() &&
92699288
(vf->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG)) &&
9270-
!bitmap_is_set(read_set, vf->field_index));
9289+
bitmap_is_set(read_set, vf->field_index));
92719290
swap_values= 1;
92729291
break;
92739292
}

storage/innobase/handler/ha_innodb.cc

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5046,14 +5046,33 @@ Ensure that indexed virtual columns will be computed.
50465046
Needs to be done for indexes that are being added with inplace ALTER
50475047
in a different thread, because from the server point of view these
50485048
columns are not yet indexed.
5049+
Also needed if the primary key is being updated.
50495050
*/
50505051
void ha_innobase::column_bitmaps_signal()
50515052
{
50525053
if (!table->vfield || table->current_lock != F_WRLCK)
50535054
return;
50545055

50555056
dict_index_t* clust_index= dict_table_get_first_index(m_prebuilt->table);
5056-
if (!clust_index->online_log)
5057+
bool is_online_log= clust_index->online_log;
5058+
5059+
/*
5060+
Check if the clustered index is being updated.
5061+
If so, it is necessary to compute virtual columns that are part of
5062+
secondary indexes, to be able to re-compute those indexes.
5063+
*/
5064+
bool upd_pk= false;
5065+
for (uint j= 0; j < clust_index->n_user_defined_cols; ++j)
5066+
{
5067+
dict_col_t *col= clust_index->fields[j].col;
5068+
if (bitmap_is_set(table->write_set, static_cast<uint>(col->ind)))
5069+
{
5070+
upd_pk= 1;
5071+
break;
5072+
}
5073+
}
5074+
5075+
if (!is_online_log && !upd_pk)
50575076
return;
50585077

50595078
uint num_v= 0;
@@ -5064,7 +5083,7 @@ void ha_innobase::column_bitmaps_signal()
50645083

50655084
dict_col_t *col= &m_prebuilt->table->v_cols[num_v].m_col;
50665085
if (col->ord_part ||
5067-
(dict_index_is_online_ddl(clust_index) &&
5086+
(is_online_log && dict_index_is_online_ddl(clust_index) &&
50685087
row_log_col_is_indexed(clust_index, num_v)))
50695088
table->mark_virtual_column_with_deps(table->vfield[j]);
50705089
num_v++;

0 commit comments

Comments
 (0)