From: Tatjana Azundris Nuernberg Date: April 1 2012 10:33am Subject: bzr push into mysql-trunk branch (tatjana.nuernberg:3827 to 3829) List-Archive: http://lists.mysql.com/commits/143395 Message-Id: <201204011033.q31AXJMo027399@acsmt356.oracle.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3829 Tatjana Azundris Nuernberg 2012-03-31 [merge] manual merge modified: mysql-test/suite/opt_trace/r/general_no_prot_all.result mysql-test/suite/opt_trace/r/general_no_prot_none.result mysql-test/suite/opt_trace/r/general_ps_prot_all.result mysql-test/suite/opt_trace/r/general_ps_prot_none.result sql/mysqld.cc sql/mysqld.h sql/sp_head.cc sql/sql_parse.cc sql/sql_parse.h sql/sql_plugin.cc 3828 Tatjana Azundris Nuernberg 2012-03-31 [merge] auto merge modified: mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test storage/innobase/row/row0mysql.cc 3827 Serge Kozlov 2012-03-30 Bug#13869905 post-fix for parts suite modified: mysql-test/suite/parts/r/rpl-partition-dml-1-1-innodb.result mysql-test/suite/parts/r/rpl-partition-dml-1-1-myisam.result mysql-test/suite/parts/r/rpl_partition.result === modified file 'mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result' --- a/mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result 2012-02-01 14:09:34 +0000 +++ b/mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result 2012-03-30 23:54:01 +0000 @@ -856,3 +856,46 @@ SELECT * FROM t2 WHERE MATCH(fts_field) id fts_field DROP TABLE t1; DROP TABLE t2; + +BUG#13701973/64274: MYSQL THREAD WAS SUSPENDED WHEN EXECUTE UPDATE QUERY + +SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; +CREATE TABLE t1 ( +t1_id INT(10) UNSIGNED NOT NULL, +t2_id INT(10) UNSIGNED DEFAULT NULL, +PRIMARY KEY (t1_id), +FOREIGN KEY (t2_id) REFERENCES t2 (t2_id) +ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB; +CREATE TABLE t2 ( +t1_id INT(10) UNSIGNED NOT NULL, +t2_id INT(10) UNSIGNED NOT NULL, +t3_id INT(10) UNSIGNED NOT NULL, +t4_id INT(10) UNSIGNED NOT NULL, +PRIMARY KEY (t2_id), +FOREIGN KEY (t1_id) REFERENCES t1 (t1_id), +FOREIGN KEY (t3_id) REFERENCES t3 (t3_id) +ON DELETE CASCADE ON UPDATE CASCADE, +FOREIGN KEY (t4_id) REFERENCES t4 (t4_id) +) ENGINE=InnoDB; +CREATE TABLE t3 ( +t3_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, +payload char(3), +PRIMARY KEY (t3_id) +) ENGINE=InnoDB; +INSERT INTO t3 VALUES (1, '100'); +CREATE TABLE t4 ( +t2_id INT(10) UNSIGNED DEFAULT NULL, +t4_id INT(10) UNSIGNED NOT NULL, +PRIMARY KEY (t4_id), +FOREIGN KEY (t2_id) REFERENCES t2 (t2_id) +ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB; +SET FOREIGN_KEY_CHECKS=1; +UPDATE t3 SET payload='101' WHERE t3_id=1; +SET FOREIGN_KEY_CHECKS=0; +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; === modified file 'mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test' --- a/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test 2011-12-20 09:45:15 +0000 +++ b/mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test 2012-03-23 08:54:26 +0000 @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# FTS with FK and update casecade +# FTS with FK and update cascade #------------------------------------------------------------------------------- --disable_warnings drop table if exists t2,t1; @@ -830,3 +830,60 @@ DROP TABLE t1; DROP TABLE t2; + +--echo +--echo BUG#13701973/64274: MYSQL THREAD WAS SUSPENDED WHEN EXECUTE UPDATE QUERY +--echo +# FTS setup did not track which tables it had already looked at to see whether +# they need initialization. Hilarity ensued when hitting circular dependencies. + +SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; + +CREATE TABLE t1 ( + t1_id INT(10) UNSIGNED NOT NULL, + t2_id INT(10) UNSIGNED DEFAULT NULL, + PRIMARY KEY (t1_id), + FOREIGN KEY (t2_id) REFERENCES t2 (t2_id) + ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB; + +CREATE TABLE t2 ( + t1_id INT(10) UNSIGNED NOT NULL, + t2_id INT(10) UNSIGNED NOT NULL, + t3_id INT(10) UNSIGNED NOT NULL, + t4_id INT(10) UNSIGNED NOT NULL, + PRIMARY KEY (t2_id), + FOREIGN KEY (t1_id) REFERENCES t1 (t1_id), + FOREIGN KEY (t3_id) REFERENCES t3 (t3_id) + ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (t4_id) REFERENCES t4 (t4_id) +) ENGINE=InnoDB; + +CREATE TABLE t3 ( + t3_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + payload char(3), + PRIMARY KEY (t3_id) +) ENGINE=InnoDB; + +INSERT INTO t3 VALUES (1, '100'); + +CREATE TABLE t4 ( + t2_id INT(10) UNSIGNED DEFAULT NULL, + t4_id INT(10) UNSIGNED NOT NULL, + PRIMARY KEY (t4_id), + FOREIGN KEY (t2_id) REFERENCES t2 (t2_id) + ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB; + +SET FOREIGN_KEY_CHECKS=1; + +UPDATE t3 SET payload='101' WHERE t3_id=1; + +SET FOREIGN_KEY_CHECKS=0; + +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; + +SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; === modified file 'mysql-test/suite/opt_trace/r/general_no_prot_all.result' --- a/mysql-test/suite/opt_trace/r/general_no_prot_all.result 2012-03-28 13:39:57 +0000 +++ b/mysql-test/suite/opt_trace/r/general_no_prot_all.result 2012-03-31 18:30:05 +0000 @@ -8198,7 +8198,7 @@ set res@1 NULL { "steps": [ ] /* steps */ } 0 0 -select d into res from t6 where d in (select f1() from t2 where s= NAME_CONST('arg',_latin1'c' COLLATE 'latin1_swedish_ci')) { +select d into res from t6 where d in (select f1() from t2 where s=arg) { "steps": [ { "join_preparation": { @@ -8838,7 +8838,7 @@ freturn 3 ret@0 { "steps": [ ] /* steps */ } 0 0 -select d+1 into res from t6 where d= NAME_CONST('res',NULL)+1 { +select d+1 into res from t6 where d=res+1 { "steps": [ { "join_preparation": { @@ -9772,7 +9772,7 @@ Warnings: Warning 1329 No data - zero rows fetched, selected, or processed select * from optt| QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES -select d into res from t6 where d in (select f1() from t2 where s= NAME_CONST('arg',_latin1'c' COLLATE 'latin1_swedish_ci')) { +select d into res from t6 where d in (select f1() from t2 where s=arg) { "steps": [ { "join_preparation": { === modified file 'mysql-test/suite/opt_trace/r/general_no_prot_none.result' --- a/mysql-test/suite/opt_trace/r/general_no_prot_none.result 2012-03-28 13:39:57 +0000 +++ b/mysql-test/suite/opt_trace/r/general_no_prot_none.result 2012-03-31 18:30:05 +0000 @@ -7145,7 +7145,7 @@ set res@1 NULL { "steps": [ ] /* steps */ } 0 0 -select d into res from t6 where d in (select f1() from t2 where s= NAME_CONST('arg',_latin1'c' COLLATE 'latin1_swedish_ci')) { +select d into res from t6 where d in (select f1() from t2 where s=arg) { "steps": [ { "join_preparation": { @@ -7920,7 +7920,7 @@ freturn 3 ret@0 { "steps": [ ] /* steps */ } 0 0 -select d+1 into res from t6 where d= NAME_CONST('res',NULL)+1 { +select d+1 into res from t6 where d=res+1 { "steps": [ { "join_preparation": { @@ -8854,7 +8854,7 @@ Warnings: Warning 1329 No data - zero rows fetched, selected, or processed select * from optt| QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES -select d into res from t6 where d in (select f1() from t2 where s= NAME_CONST('arg',_latin1'c' COLLATE 'latin1_swedish_ci')) { +select d into res from t6 where d in (select f1() from t2 where s=arg) { "steps": [ { "join_preparation": { === modified file 'mysql-test/suite/opt_trace/r/general_ps_prot_all.result' --- a/mysql-test/suite/opt_trace/r/general_ps_prot_all.result 2012-03-28 13:39:57 +0000 +++ b/mysql-test/suite/opt_trace/r/general_ps_prot_all.result 2012-03-31 18:30:05 +0000 @@ -8159,7 +8159,7 @@ set res@1 NULL { "steps": [ ] /* steps */ } 0 0 -select d into res from t6 where d in (select f1() from t2 where s= NAME_CONST('arg',_latin1'c' COLLATE 'latin1_swedish_ci')) { +select d into res from t6 where d in (select f1() from t2 where s=arg) { "steps": [ { "join_preparation": { @@ -8799,7 +8799,7 @@ freturn 3 ret@0 { "steps": [ ] /* steps */ } 0 0 -select d+1 into res from t6 where d= NAME_CONST('res',NULL)+1 { +select d+1 into res from t6 where d=res+1 { "steps": [ { "join_preparation": { @@ -9747,7 +9747,7 @@ Warnings: Warning 1329 No data - zero rows fetched, selected, or processed select * from optt| QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES -select d into res from t6 where d in (select f1() from t2 where s= NAME_CONST('arg',_latin1'c' COLLATE 'latin1_swedish_ci')) { +select d into res from t6 where d in (select f1() from t2 where s=arg) { "steps": [ { "join_preparation": { === modified file 'mysql-test/suite/opt_trace/r/general_ps_prot_none.result' --- a/mysql-test/suite/opt_trace/r/general_ps_prot_none.result 2012-03-28 13:39:57 +0000 +++ b/mysql-test/suite/opt_trace/r/general_ps_prot_none.result 2012-03-31 18:30:05 +0000 @@ -7066,7 +7066,7 @@ set res@1 NULL { "steps": [ ] /* steps */ } 0 0 -select d into res from t6 where d in (select f1() from t2 where s= NAME_CONST('arg',_latin1'c' COLLATE 'latin1_swedish_ci')) { +select d into res from t6 where d in (select f1() from t2 where s=arg) { "steps": [ { "join_preparation": { @@ -7841,7 +7841,7 @@ freturn 3 ret@0 { "steps": [ ] /* steps */ } 0 0 -select d+1 into res from t6 where d= NAME_CONST('res',NULL)+1 { +select d+1 into res from t6 where d=res+1 { "steps": [ { "join_preparation": { @@ -8789,7 +8789,7 @@ Warnings: Warning 1329 No data - zero rows fetched, selected, or processed select * from optt| QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES -select d into res from t6 where d in (select f1() from t2 where s= NAME_CONST('arg',_latin1'c' COLLATE 'latin1_swedish_ci')) { +select d into res from t6 where d in (select f1() from t2 where s=arg) { "steps": [ { "join_preparation": { === modified file 'sql/mysqld.cc' --- a/sql/mysqld.cc 2012-03-22 06:25:38 +0000 +++ b/sql/mysqld.cc 2012-03-31 18:30:05 +0000 @@ -402,6 +402,8 @@ ulong slow_start_timeout; SQL commands in the init file and in --bootstrap mode. */ bool in_bootstrap= FALSE; +my_bool opt_bootstrap; + /** @brief 'grant_option' is used to indicate if privileges needs to be checked, in which case the lock, LOCK_grant, is used @@ -716,7 +718,7 @@ char *opt_logname, *opt_slow_logname, *o static volatile sig_atomic_t kill_in_progress; -static my_bool opt_bootstrap, opt_myisam_log; +static my_bool opt_myisam_log; static int cleanup_done; static ulong opt_specialflag; static char *opt_update_logname; === modified file 'sql/mysqld.h' --- a/sql/mysqld.h 2012-03-28 13:39:57 +0000 +++ b/sql/mysqld.h 2012-03-31 18:30:05 +0000 @@ -107,6 +107,7 @@ extern bool opt_ignore_builtin_innodb; extern my_bool opt_character_set_client_handshake; extern bool volatile abort_loop; extern bool in_bootstrap; +extern my_bool opt_bootstrap; extern uint connection_count; extern my_bool opt_safe_user_create; extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; === modified file 'sql/sp_head.cc' --- a/sql/sp_head.cc 2012-03-21 14:49:40 +0000 +++ b/sql/sp_head.cc 2012-03-31 18:30:05 +0000 @@ -3055,51 +3055,115 @@ int sp_instr::exec_core(THD *thd, uint * int sp_instr_stmt::execute(THD *thd, uint *nextp) { - int res; + int res= 0; + bool need_subst; + DBUG_ENTER("sp_instr_stmt::execute"); DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command())); const CSET_STRING query_backup= thd->query_string; + #if defined(ENABLED_PROFILING) /* This s-p instr is profilable and will be captured. */ thd->profiling.set_query_source(m_query.str, m_query.length); #endif - if (!(res= alloc_query(thd, m_query.str, m_query.length)) && - !(res=subst_spvars(thd, this, &m_query))) + + /* + If we can't set thd->query_string at all, we give up on this statement. + */ + if (alloc_query(thd, m_query.str, m_query.length)) + DBUG_RETURN(TRUE); + + /* + Check whether we actually need a substitution of SP variables with + NAME_CONST(...) (using subst_spvars()). + If both of the following apply, we won't need to substitute: + + - general log is off + + - binary logging is off, or not in statement mode + + We don't have to substitute on behalf of the query cache as + queries with SP vars are not cached, anyway. + + query_name_consts is used elsewhere in a special case concerning + CREATE TABLE, but we do not need to do anything about that here. + + The slow query log is another special case: we won't know whether a + query qualifies for the slow query log until after it's been + executed. We assume that most queries are not slow, so we do not + pre-emptively substitute just for the slow query log. If a query + ends up being slow after all and we haven't done the substitution + already for any of the above (general log etc.), we'll do the + substitution immediately before writing to the log. + */ + + need_subst= ((thd->variables.option_bits & OPTION_LOG_OFF) && + (!(thd->variables.option_bits & OPTION_BIN_LOG) || + !mysql_bin_log.is_open() || + thd->is_current_stmt_binlog_format_row())) ? FALSE : TRUE; + + /* + If we need to do a substitution but can't (OOM), give up. + */ + + if (need_subst && subst_spvars(thd, this, &m_query)) + DBUG_RETURN(TRUE); + + /* + (the order of query cache and subst_spvars calls is irrelevant because + queries with SP vars can't be cached) + */ + if (unlikely((thd->variables.option_bits & OPTION_LOG_OFF)==0)) + general_log_write(thd, COM_QUERY, thd->query(), thd->query_length()); + + if (query_cache_send_result_to_client(thd, thd->query(), + thd->query_length()) <= 0) { - /* - (the order of query cache and subst_spvars calls is irrelevant because - queries with SP vars can't be cached) - */ - if (unlikely((thd->variables.option_bits & OPTION_LOG_OFF)==0)) - general_log_write(thd, COM_QUERY, thd->query(), thd->query_length()); + res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this); - if (query_cache_send_result_to_client(thd, thd->query(), - thd->query_length()) <= 0) + if (thd->get_stmt_da()->is_eof()) { - res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this); - - if (thd->get_stmt_da()->is_eof()) - { - /* Finalize server status flags after executing a statement. */ - thd->update_server_status(); + /* Finalize server status flags after executing a statement. */ + thd->update_server_status(); - thd->protocol->end_statement(); - } + thd->protocol->end_statement(); + } - query_cache_end_of_result(thd); + query_cache_end_of_result(thd); - if (!res && unlikely(thd->enable_slow_log)) - log_slow_statement(thd); + if (!res && unlikely(log_slow_applicable(thd))) + { + /* + We actually need to write the slow log. Check whether we already + called subst_spvars() above, otherwise, do it now. In the highly + unlikely event of subst_spvars() failing (OOM), we'll try to log + the unmodified statement instead. + */ + if (!need_subst) + res= subst_spvars(thd, this, &m_query); + log_slow_do(thd); } - else - *nextp= m_ip+1; - thd->set_query(query_backup); - thd->query_name_consts= 0; - if (!thd->is_error()) - thd->get_stmt_da()->reset_diagnostics_area(); + /* + With the current setup, a subst_spvars() and a mysql_rewrite_query() + (rewriting passwords etc.) will not both happen to a query. + If this ever changes, we give the engineer pause here so they will + double-check whether the potential conflict they created is a + problem. + */ + DBUG_ASSERT((thd->query_name_consts == 0) || + (thd->rewritten_query.length() == 0)); } + else + *nextp= m_ip+1; + + thd->set_query(query_backup); + thd->query_name_consts= 0; + + if (!thd->is_error()) + thd->get_stmt_da()->reset_diagnostics_area(); + DBUG_RETURN(res || thd->is_error()); } === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2012-03-30 15:38:01 +0000 +++ b/sql/sql_parse.cc 2012-03-31 18:30:05 +0000 @@ -1685,9 +1685,22 @@ bool dispatch_command(enum enum_server_c } -void log_slow_statement(THD *thd) +/** + Check whether we need to write the current statement (or its rewritten + version if it exists) to the slow query log. + As a side-effect, a digest of suppressed statements may be written. + + @param thd thread handle + + @retval + true statement needs to be logged + @retval + false statement does not need to be logged +*/ + +bool log_slow_applicable(THD *thd) { - DBUG_ENTER("log_slow_statement"); + DBUG_ENTER("log_slow_applicable"); /* The following should never be true with our current code base, @@ -1695,7 +1708,7 @@ void log_slow_statement(THD *thd) statement in a trigger or stored function */ if (unlikely(thd->in_sub_stmt)) - DBUG_VOID_RETURN; // Don't set time for sub stmt + DBUG_RETURN(false); // Don't set time for sub stmt /* Do not log administrative statements unless the appropriate option is @@ -1716,18 +1729,57 @@ void log_slow_statement(THD *thd) bool suppress_logging= log_throttle_qni.log(thd, warn_no_index); if (!suppress_logging && log_this_query) - { - THD_STAGE_INFO(thd, stage_logging_slow_query); - thd->status_var.long_query_count++; - - if (thd->rewritten_query.length()) - slow_log_print(thd, - thd->rewritten_query.c_ptr_safe(), - thd->rewritten_query.length()); - else - slow_log_print(thd, thd->query(), thd->query_length()); - } + DBUG_RETURN(true); } + DBUG_RETURN(false); +} + + +/** + Unconditionally the current statement (or its rewritten version if it + exists) to the slow query log. + + @param thd thread handle +*/ + +void log_slow_do(THD *thd) +{ + DBUG_ENTER("log_slow_do"); + + THD_STAGE_INFO(thd, stage_logging_slow_query); + thd->status_var.long_query_count++; + + if (thd->rewritten_query.length()) + slow_log_print(thd, + thd->rewritten_query.c_ptr_safe(), + thd->rewritten_query.length()); + else + slow_log_print(thd, thd->query(), thd->query_length()); + + DBUG_VOID_RETURN; +} + + +/** + Check whether we need to write the current statement to the slow query + log. If so, do so. This is a wrapper for the two functions above; + most callers should use this wrapper. Only use the above functions + directly if you have expensive rewriting that you only need to do if + the query actually needs to be logged (e.g. SP variables / NAME_CONST + substitution when executing a PROCEDURE). + A digest of suppressed statements may be logged instead of the current + statement. + + @param thd thread handle +*/ + +void log_slow_statement(THD *thd) +{ + DBUG_ENTER("log_slow_statement"); + + if (log_slow_applicable(thd)) + log_slow_do(thd); + DBUG_VOID_RETURN; } === modified file 'sql/sql_parse.h' --- a/sql/sql_parse.h 2012-01-16 22:21:16 +0000 +++ b/sql/sql_parse.h 2012-03-31 18:30:05 +0000 @@ -104,6 +104,8 @@ void do_handle_bootstrap(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length); void log_slow_statement(THD *thd); +bool log_slow_applicable(THD *thd); +void log_slow_do(THD *thd); bool append_file_to_dir(THD *thd, const char **filename_ptr, const char *table_name); bool append_file_to_dir(THD *thd, const char **filename_ptr, === modified file 'sql/sql_plugin.cc' --- a/sql/sql_plugin.cc 2012-03-14 01:50:20 +0000 +++ b/sql/sql_plugin.cc 2012-03-31 18:30:05 +0000 @@ -1003,7 +1003,8 @@ static void reap_plugins(void) list= reap; while ((plugin= *(--list))) { - sql_print_information("Shutting down plugin '%s'", plugin->name.str); + if (!opt_bootstrap) + sql_print_information("Shutting down plugin '%s'", plugin->name.str); plugin_deinitialize(plugin, true); } === modified file 'storage/innobase/row/row0mysql.cc' --- a/storage/innobase/row/row0mysql.cc 2012-03-29 11:19:57 +0000 +++ b/storage/innobase/row/row0mysql.cc 2012-03-30 23:54:01 +0000 @@ -1531,16 +1531,18 @@ void init_fts_doc_id_for_ref( /*====================*/ dict_table_t* table, /*!< in: table */ - ulint depth) /*!< in: recusive call depth */ + ulint* depth) /*!< in: recusive call depth */ { dict_foreign_t* foreign; foreign = UT_LIST_GET_FIRST(table->referenced_list); - depth++; + table->fk_max_recusive_level = 0; + + (*depth)++; /* Limit on tables involved in cascading delete/update */ - if (depth > FK_MAX_CASCADE_DEL) { + if (*depth > FK_MAX_CASCADE_DEL) { return; } @@ -1581,6 +1583,7 @@ row_update_for_mysql( upd_node_t* node; dict_table_t* table = prebuilt->table; trx_t* trx = prebuilt->trx; + ulint fk_depth = 0; ut_ad(prebuilt && trx); UT_NOT_USED(mysql_rec); @@ -1631,7 +1634,7 @@ row_update_for_mysql( row_mysql_delay_if_needed(); - init_fts_doc_id_for_ref(table, 0); + init_fts_doc_id_for_ref(table, &fk_depth); trx_start_if_not_started_xa(trx); No bundle (reason: useless for push emails).