diff --git a/sql/handler.cc b/sql/handler.cc index f642264..2ee7b4c 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2496,11 +2496,19 @@ int ha_prepare_low(THD *thd, bool all) all ? Transaction_ctx::SESSION : Transaction_ctx::STMT; Ha_trx_info *ha_info= thd->get_transaction()->ha_trx_info(trx_scope); + // TDSQL: Special handling of XA COMMIT ONE PHASE, swap order of innodb and binlog, + // do innodb prepare first. + const bool is_xa_cop= + (thd->lex->sql_command == SQLCOM_XA_COMMIT && + static_cast(thd->lex->m_sql_cmd)->get_xa_opt() == XA_ONE_PHASE); + + handlerton *ht0 = NULL; + DBUG_ENTER("ha_prepare_low"); if (ha_info) { - for (; ha_info && !error; ha_info= ha_info->next()) + while (ha_info && !error) { int err= 0; handlerton *ht= ha_info->ht(); @@ -2508,15 +2516,42 @@ int ha_prepare_low(THD *thd, bool all) Do not call two-phase commit if this particular transaction is read-only. This allows for simpler implementation in engines that are always read-only. + For binlog psuedo SE, it's always read-write. */ if (!ha_info->is_trx_read_write()) continue; + if (ht0 == NULL && is_xa_cop && ht->prepare == binlog_prepare) + { + Ha_trx_info *ha_info_tmp= ha_info->next(); + if (ha_info_tmp) + { + ha_info= ha_info_tmp; + ht0= ht; + continue; + } + } +again: if ((err= ht->prepare(ht, thd, all))) { my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); error= 1; } thd->status_var.ha_prepare_count++; + + if (!ha_info) + break; // binlog_prepare() is just called. + + ha_info= ha_info->next(); + if (!ha_info && ht0) + { + /* + Run binlog_prepare() at last, after all engines have prepared. + */ + DBUG_ASSERT(is_xa_cop); + ht= ht0; + ht0= NULL; + goto again; + } } DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE();); }