diff options
author | Nikita Malyavin <nikitamalyavin@gmail.com> | 2022-07-22 02:18:21 +0300 |
---|---|---|
committer | Nikita Malyavin <nikitamalyavin@gmail.com> | 2022-08-23 16:36:28 +0300 |
commit | ca4f84b95b42a87ca9f828ec2b963c91a1e308d6 (patch) | |
tree | 875013c3a692273971ea12c396311ff7edcf73ab | |
parent | 955fceb53fdc98996b087ff901bae70031543ed2 (diff) | |
download | mariadb-git-bb-10.10-MDEV-29181.tar.gz |
MDEV-29068 Cascade foreign key updates do not apply in online alterbb-10.10-MDEV-29181
Foreign key cascade operations are still implemented through innodb.
Add support for online logging in row_ins_foreign_check_on_constraint.
upd_node_t::sql_is_online_alter is added to reuse cascade->row and
cascade->upd_row.
-rw-r--r-- | mysql-test/main/alter_table_online_debug.result | 326 | ||||
-rw-r--r-- | mysql-test/main/alter_table_online_debug.test | 166 | ||||
-rw-r--r-- | sql/sql_class.cc | 29 | ||||
-rw-r--r-- | sql/table.h | 9 | ||||
-rw-r--r-- | storage/innobase/btr/btr0cur.cc | 3 | ||||
-rw-r--r-- | storage/innobase/row/row0ins.cc | 108 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.cc | 11 |
7 files changed, 649 insertions, 3 deletions
diff --git a/mysql-test/main/alter_table_online_debug.result b/mysql-test/main/alter_table_online_debug.result index 18b552ca53a..2797d691174 100644 --- a/mysql-test/main/alter_table_online_debug.result +++ b/mysql-test/main/alter_table_online_debug.result @@ -1072,5 +1072,331 @@ xa rollback 'xid'; drop table t; set debug_sync= reset; # +# MDEV-29068 Cascade foreign key updates do not apply in online alter +# +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +create table t2 (b int, foreign key (b) references t1 (a) on delete cascade on update cascade) +engine=innodb; +insert into t2 values (1),(2),(3); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add c int default(b), algorithm=copy, lock=none; +connection default; +update t1 set a = 22 where a = 2; +set debug_sync= 'now signal goforit'; +connection con2; +select * from t2; +b c +1 1 +22 22 +3 3 +connection default; +drop table t2, t1; +set debug_sync= reset; +# +# Big BLOB +# +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +create table t2 (a int, b text, +foreign key (a) references t1 (a) on delete cascade on update cascade) +engine=innodb ROW_FORMAT=COMPRESSED; +insert into t2 values (1, NULL),(2, REPEAT('a', 65535)),(3, 'xyz'); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add c int default(a), algorithm=copy, lock=none; +connection default; +update t1 set a = 22 where a = 2; +delete from t1 where a = 3; +set debug_sync= 'now signal goforit'; +connection con2; +select a, if(b = REPEAT('a', 65535), 1, b) from t2; +a if(b = REPEAT('a', 65535), 1, b) +1 NULL +22 1 +connection default; +drop table t2, t1; +set debug_sync= reset; +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +create table t2 (a int, b text, +foreign key (a) references t1 (a) on delete cascade on update cascade) +engine=innodb ROW_FORMAT=DYNAMIC; +insert into t2 values (1, NULL),(2, REPEAT('a', 65535)),(3, 'xyz'); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add c int default(a), algorithm=copy, lock=none; +connection default; +update t1 set a = 22 where a = 2; +delete from t1 where a = 3; +set debug_sync= 'now signal goforit'; +connection con2; +select a, if(b = REPEAT('a', 65535), 1, b) from t2; +a if(b = REPEAT('a', 65535), 1, b) +1 NULL +22 1 +connection default; +drop table t2, t1; +set debug_sync= reset; +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +create table t2 (a int, b text, +foreign key (a) references t1 (a) on delete cascade on update cascade) +engine=innodb ROW_FORMAT=COMPACT; +insert into t2 values (1, NULL),(2, REPEAT('a', 65535)),(3, 'xyz'); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add c int default(a), algorithm=copy, lock=none; +connection default; +update t1 set a = 22 where a = 2; +delete from t1 where a = 3; +set debug_sync= 'now signal goforit'; +connection con2; +select a, if(b = REPEAT('a', 65535), 1, b) from t2; +a if(b = REPEAT('a', 65535), 1, b) +1 NULL +22 1 +connection default; +drop table t2, t1; +set debug_sync= reset; +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +create table t2 (a int, b text, +foreign key (a) references t1 (a) on delete cascade on update cascade) +engine=innodb ROW_FORMAT=REDUNDANT; +insert into t2 values (1, NULL),(2, REPEAT('a', 65535)),(3, 'xyz'); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add c int default(a), algorithm=copy, lock=none; +connection default; +update t1 set a = 22 where a = 2; +delete from t1 where a = 3; +set debug_sync= 'now signal goforit'; +connection con2; +select a, if(b = REPEAT('a', 65535), 1, b) from t2; +a if(b = REPEAT('a', 65535), 1, b) +1 NULL +22 1 +connection default; +drop table t2, t1; +set debug_sync= reset; +# +# VCOLs +# +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +create table t2 (a int, b text as (REPEAT('a', 65535)), key(b(20)), +foreign key (a) references t1 (a) on delete cascade on update cascade) +engine=innodb; +insert into t2(a) values (1),(2),(3); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add c int default(a), algorithm=copy, lock=none; +connection default; +update t1 set a = 22 where a = 2; +set debug_sync= 'now signal goforit'; +connection con2; +select a, if(length(b) > 1, b = REPEAT('a', 65535), b) from t2; +a if(length(b) > 1, b = REPEAT('a', 65535), b) +1 1 +22 1 +3 1 +connection default; +drop table t2, t1; +set debug_sync= reset; +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +create table t2 (a int, b text, c text as (b), +foreign key (a) references t1 (a) on delete cascade on update cascade) +engine=innodb; +insert into t2(a, b) values (1, NULL),(2, REPEAT('a', 65535)),(3, 'x'); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add d char DEFAULT(SUBSTR(b, 1, 1)), algorithm=copy, lock=none; +connection default; +update t1 set a = 22 where a = 2; +delete from t1 where a = 3; +set debug_sync= 'now signal goforit'; +connection con2; +select a, if(length(b) > 1, b = REPEAT('a', 65535), b), c = b, d from t2; +a if(length(b) > 1, b = REPEAT('a', 65535), b) c = b d +1 NULL NULL NULL +22 1 1 a +connection default; +drop table t2, t1; +set debug_sync= reset; +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +create table t2 (b int, foreign key (b) references t1 (a) on delete set null on update set null) +engine=innodb; +insert into t2 values (1),(2),(3); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add c int default(b), algorithm=copy, lock=none; +connection default; +update t1 set a = 22 where a = 2; +set debug_sync= 'now signal goforit'; +connection con2; +select * from t2; +b c +1 1 +NULL NULL +3 3 +connection default; +drop table t2, t1; +set debug_sync= reset; +# +# Big BLOB +# +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +create table t2 (a int, b text, +foreign key (a) references t1 (a) on delete set null on update set null) +engine=innodb ROW_FORMAT=COMPRESSED; +insert into t2 values (1, NULL),(2, REPEAT('a', 65535)),(3, 'xyz'); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add c int default(a), algorithm=copy, lock=none; +connection default; +update t1 set a = 22 where a = 2; +delete from t1 where a = 3; +set debug_sync= 'now signal goforit'; +connection con2; +select a, if(b = REPEAT('a', 65535), 1, b) from t2; +a if(b = REPEAT('a', 65535), 1, b) +1 NULL +NULL 1 +NULL xyz +connection default; +drop table t2, t1; +set debug_sync= reset; +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +create table t2 (a int, b text, +foreign key (a) references t1 (a) on delete set null on update set null) +engine=innodb ROW_FORMAT=DYNAMIC; +insert into t2 values (1, NULL),(2, REPEAT('a', 65535)),(3, 'xyz'); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add c int default(a), algorithm=copy, lock=none; +connection default; +update t1 set a = 22 where a = 2; +delete from t1 where a = 3; +set debug_sync= 'now signal goforit'; +connection con2; +select a, if(b = REPEAT('a', 65535), 1, b) from t2; +a if(b = REPEAT('a', 65535), 1, b) +1 NULL +NULL 1 +NULL xyz +connection default; +drop table t2, t1; +set debug_sync= reset; +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +create table t2 (a int, b text, +foreign key (a) references t1 (a) on delete set null on update set null) +engine=innodb ROW_FORMAT=COMPACT; +insert into t2 values (1, NULL),(2, REPEAT('a', 65535)),(3, 'xyz'); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add c int default(a), algorithm=copy, lock=none; +connection default; +update t1 set a = 22 where a = 2; +delete from t1 where a = 3; +set debug_sync= 'now signal goforit'; +connection con2; +select a, if(b = REPEAT('a', 65535), 1, b) from t2; +a if(b = REPEAT('a', 65535), 1, b) +1 NULL +NULL 1 +NULL xyz +connection default; +drop table t2, t1; +set debug_sync= reset; +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +create table t2 (a int, b text, +foreign key (a) references t1 (a) on delete set null on update set null) +engine=innodb ROW_FORMAT=REDUNDANT; +insert into t2 values (1, NULL),(2, REPEAT('a', 65535)),(3, 'xyz'); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add c int default(a), algorithm=copy, lock=none; +connection default; +update t1 set a = 22 where a = 2; +delete from t1 where a = 3; +set debug_sync= 'now signal goforit'; +connection con2; +select a, if(b = REPEAT('a', 65535), 1, b) from t2; +a if(b = REPEAT('a', 65535), 1, b) +1 NULL +NULL 1 +NULL xyz +connection default; +drop table t2, t1; +set debug_sync= reset; +# +# VCOLs +# +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +create table t2 (a int, b text as (REPEAT('a', 65535)), key(b(20)), +foreign key (a) references t1 (a) on delete set null on update set null) +engine=innodb; +insert into t2(a) values (1),(2),(3); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add c int default(a), algorithm=copy, lock=none; +connection default; +update t1 set a = 22 where a = 2; +set debug_sync= 'now signal goforit'; +connection con2; +select a, if(length(b) > 1, b = REPEAT('a', 65535), b) from t2; +a if(length(b) > 1, b = REPEAT('a', 65535), b) +1 1 +NULL 1 +3 1 +connection default; +drop table t2, t1; +set debug_sync= reset; +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +create table t2 (a int, b text, c text as (b), +foreign key (a) references t1 (a) on delete set null on update set null) +engine=innodb; +insert into t2(a, b) values (1, NULL),(2, REPEAT('a', 65535)),(3, 'x'); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add d char DEFAULT(SUBSTR(b, 1, 1)), algorithm=copy, lock=none; +connection default; +update t1 set a = 22 where a = 2; +delete from t1 where a = 3; +set debug_sync= 'now signal goforit'; +connection con2; +select a, if(length(b) > 1, b = REPEAT('a', 65535), b), c = b, d from t2; +a if(length(b) > 1, b = REPEAT('a', 65535), b) c = b d +1 NULL NULL NULL +NULL 1 1 a +NULL x 1 x +connection default; +drop table t2, t1; +set debug_sync= reset; +# # End of 10.10 tests # diff --git a/mysql-test/main/alter_table_online_debug.test b/mysql-test/main/alter_table_online_debug.test index 719eb4c477d..cdf41622b22 100644 --- a/mysql-test/main/alter_table_online_debug.test +++ b/mysql-test/main/alter_table_online_debug.test @@ -1251,6 +1251,172 @@ xa rollback 'xid'; drop table t; set debug_sync= reset; + +--echo # +--echo # MDEV-29068 Cascade foreign key updates do not apply in online alter +--echo # + +--let $cascade_rule= on delete cascade on update cascade + +--let $i=2 + +--while ($i) { + +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +eval create table t2 (b int, foreign key (b) references t1 (a) $cascade_rule) + engine=innodb; +insert into t2 values (1),(2),(3); +--send +set debug_sync= 'now wait_for downgraded'; + +--connection con2 +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +--send +alter table t2 add c int default(b), algorithm=copy, lock=none; + +--connection default +--reap +update t1 set a = 22 where a = 2; +set debug_sync= 'now signal goforit'; + +--connection con2 +--reap +select * from t2; + +# Cleanup +--connection default +drop table t2, t1; +set debug_sync= reset; + +--echo # +--echo # Big BLOB +--echo # +--let $j = 4 +--while($j){ +--let $jj=$j +--dec $jj +--if (!$jj){ +--let $row_format=REDUNDANT +--} +--dec $jj +--if (!$jj){ +--let $row_format=COMPACT +--} +--dec $jj +--if (!$jj){ +--let $row_format=DYNAMIC +--} +--dec $jj +--if (!$jj){ +--let $row_format=COMPRESSED +--} + +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +eval create table t2 (a int, b text, + foreign key (a) references t1 (a) $cascade_rule) + engine=innodb ROW_FORMAT=$row_format; +insert into t2 values (1, NULL),(2, REPEAT('a', 65535)),(3, 'xyz'); +--send +set debug_sync= 'now wait_for downgraded'; + +--connection con2 + +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +--send +alter table t2 add c int default(a), algorithm=copy, lock=none; + +--connection default +--reap +update t1 set a = 22 where a = 2; +delete from t1 where a = 3; +set debug_sync= 'now signal goforit'; + +--connection con2 +--reap +select a, if(b = REPEAT('a', 65535), 1, b) from t2; + +# Cleanup +--connection default +drop table t2, t1; +set debug_sync= reset; + +--dec $j +# End while($j) +--} + + +--echo # +--echo # VCOLs +--echo # + +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +eval create table t2 (a int, b text as (REPEAT('a', 65535)), key(b(20)), + foreign key (a) references t1 (a) $cascade_rule) + engine=innodb; +insert into t2(a) values (1),(2),(3); +--send +set debug_sync= 'now wait_for downgraded'; + +--connection con2 + +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +--send +alter table t2 add c int default(a), algorithm=copy, lock=none; + +--connection default +--reap +update t1 set a = 22 where a = 2; +set debug_sync= 'now signal goforit'; + +--connection con2 +--reap +select a, if(length(b) > 1, b = REPEAT('a', 65535), b) from t2; + +# Cleanup +--connection default +drop table t2, t1; +set debug_sync= reset; + + +create table t1 (a int primary key) engine=innodb; +insert into t1 values (1),(2),(3); +eval create table t2 (a int, b text, c text as (b), + foreign key (a) references t1 (a) $cascade_rule) + engine=innodb; +insert into t2(a, b) values (1, NULL),(2, REPEAT('a', 65535)),(3, 'x'); +--send +set debug_sync= 'now wait_for downgraded'; + +--connection con2 + +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +--send +alter table t2 add d char DEFAULT(SUBSTR(b, 1, 1)), algorithm=copy, lock=none; + +--connection default +--reap +update t1 set a = 22 where a = 2; +delete from t1 where a = 3; +set debug_sync= 'now signal goforit'; + +--connection con2 +--reap +select a, if(length(b) > 1, b = REPEAT('a', 65535), b), c = b, d from t2; + +# Cleanup +--connection default +drop table t2, t1; +set debug_sync= reset; + +--let $cascade_rule= on delete set null on update set null +--dec $i +# End while ($i) +--} + + --echo # --echo # End of 10.10 tests --echo # diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 351d0d3ad13..7bc048b3634 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -8180,3 +8180,32 @@ void Charset_loader_server::raise_not_applicable_error(const char *cs, { my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), cl, cs); } + + +int sql_log_cascade_update(TABLE *table) +{ +#ifdef HAVE_REPLICATION + DBUG_ASSERT(table->s->online_alter_binlog); + Log_func *log_func= Update_rows_log_event::binlog_row_logging_function; + bitmap_set_all(&table->def_read_set); + return binlog_log_row_online_alter(table, table->record[0], table->record[1], + log_func); +#else + DBUG_ASSERT(0); + return 1; // Will report corruption in innodb +#endif +} + + +int sql_log_cascade_delete(TABLE *table) +{ +#ifdef HAVE_REPLICATION + DBUG_ASSERT(table->s->online_alter_binlog); + Log_func *log_func= Delete_rows_log_event::binlog_row_logging_function; + bitmap_set_all(&table->def_read_set); + return binlog_log_row_online_alter(table, table->record[0], NULL, log_func); +#else + DBUG_ASSERT(0); + return 1; // Will report corruption in innodb +#endif +} diff --git a/sql/table.h b/sql/table.h index e8abf10af89..a54dcae9958 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1567,6 +1567,15 @@ public: online_alter_cache_data *online_alter_cache; + bool is_online_alter() const + { +#ifdef HAVE_REPLICATION + return s->online_alter_binlog != NULL; +#else + return false; +#endif + } + inline void reset() { bzero((void*)this, sizeof(*this)); } void init(THD *thd, TABLE_LIST *tl); bool fill_item_list(List<Item> *item_list) const; diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index b4cee3acb53..ac5b36bdcf0 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -7868,6 +7868,9 @@ btr_copy_externally_stored_field( buf = (byte*) mem_heap_alloc(heap, local_len + extern_len); + if (UNIV_UNLIKELY(buf == NULL)) + return NULL; + memcpy(buf, data, local_len); *len = local_len + btr_copy_externally_stored_field_prefix_low(buf + local_len, diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 4f807fdd7ed..bbe245b0002 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -43,6 +43,7 @@ Created 4/20/1996 Heikki Tuuri #include "buf0lru.h" #include "fts0fts.h" #include "fts0types.h" +#include "ha_innodb.h" #ifdef BTR_CUR_HASH_ADAPT # include "btr0sea.h" #endif @@ -50,6 +51,8 @@ Created 4/20/1996 Heikki Tuuri #include "wsrep_mysqld.h" #endif /* WITH_WSREP */ +#include "scope.h" + /************************************************************************* IMPORTANT NOTE: Any operation that generates redo MUST check that there is enough space in the redo log before for that operation. This is @@ -978,6 +981,107 @@ dberr_t wsrep_append_foreign_key(trx_t *trx, Wsrep_service_key_type key_type); #endif /* WITH_WSREP */ + +int sql_log_cascade_update(TABLE *table); +int sql_log_cascade_delete(TABLE *table); + +static bool row_ins_store_row_in_mysql(dtuple_t *row, + row_prebuilt_t *prebuilt, + uchar *mysql_rec) +{ + mysql_row_templ_t *templ= prebuilt->mysql_template; + for (uint i = 0; i < prebuilt->n_template; i++) + { + const dfield_t* df= dtuple_get_nth_field(row, i); + byte null_mask= static_cast<byte>(templ->mysql_null_bit_mask); + + if (dfield_is_null(df)) + { + mysql_rec[templ->mysql_null_byte_offset]|= null_mask; + } + else + { + if (templ->mysql_null_bit_mask) + mysql_rec[templ->mysql_null_byte_offset]&= (uchar)~null_mask; + + byte *data= static_cast<byte*>(df->data); + ulint len= df->len; + + if (dfield_is_ext(df)) + { + data= btr_copy_externally_stored_field(&len, data, + prebuilt->table->space->zip_size(), + len, prebuilt->blob_heap); + if (UNIV_UNLIKELY(data == NULL)) + return false; + } + + row_sel_field_store_in_mysql_format(mysql_rec + templ->mysql_col_offset, + templ, prebuilt->index, + templ->clust_rec_field_no, + data, len); + } + + templ++; + } + return true; +} + +static dberr_t report_row_update(upd_node_t *cascade, + dict_index_t* clust_index) +{ + row_prebuilt_t *prebuilt= cascade->prebuilt; + prebuilt->index= clust_index; + TABLE *maria_table= prebuilt->m_mysql_table; + + ulint n_ext= dtuple_get_n_ext(cascade->row) + + (cascade->is_delete ? 0 : dtuple_get_n_ext(cascade->upd_row)); + + auto _= make_scope_exit([cascade, prebuilt, n_ext](){ + + cascade->row= NULL; + cascade->ext= NULL; + cascade->upd_row= NULL; + cascade->upd_ext= NULL; + mem_heap_empty(cascade->heap); + if (n_ext && prebuilt->blob_heap) + { + mem_heap_free(prebuilt->blob_heap); + prebuilt->blob_heap= NULL; + } + }); + + if (n_ext) + { + if (UNIV_UNLIKELY(prebuilt->blob_heap != NULL)) + mem_heap_empty(prebuilt->blob_heap); + prebuilt->blob_heap= mem_heap_create(srv_page_size); + + if (UNIV_UNLIKELY(prebuilt->blob_heap == NULL)) + return DB_OUT_OF_MEMORY; + } + + if (UNIV_UNLIKELY(!row_ins_store_row_in_mysql(cascade->row, prebuilt, + maria_table->record[0]))) + return DB_OUT_OF_MEMORY; + + if (cascade->is_delete) + { + if (UNIV_UNLIKELY(sql_log_cascade_delete(maria_table))) + return DB_ERROR; + } + else + { + if (UNIV_UNLIKELY(!row_ins_store_row_in_mysql(cascade->upd_row, prebuilt, + maria_table->record[1]))) + return DB_OUT_OF_MEMORY; + if (UNIV_UNLIKELY(sql_log_cascade_update(maria_table))) + return DB_ERROR; + } + + return DB_SUCCESS; +} + /*********************************************************************//** Perform referential actions or checks when a parent row is deleted or updated and the constraint had an ON DELETE or ON UPDATE condition which was not @@ -1352,6 +1456,10 @@ row_ins_foreign_check_on_constraint( err = row_update_cascade_for_mysql(thr, cascade, foreign->foreign_table); + if (UNIV_UNLIKELY(prebuilt->m_mysql_table->is_online_alter()) + && UNIV_LIKELY(!err)) + err = report_row_update(cascade, clust_index); + mtr_start(mtr); /* Restore pcur position */ diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 3a4b9554581..8cff74ced84 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -2854,9 +2854,14 @@ row_upd( ut_ad(err == DB_SUCCESS); - /* Do some cleanup */ - - if (node->row != NULL) { + /* Do some cleanup. + If it is a cascade update/delete during ONLINE ALTER TABLE, + this row data will be used later for reporting row changes to sql. + See report_row_update(). */ + + if (node->row != NULL + && !(node->foreign + && node->prebuilt->m_mysql_table->is_online_alter())) { node->row = NULL; node->ext = NULL; node->upd_row = NULL; |