mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
(pushing for Andrei)
Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack Once had been set the flag might later got reset inside of a stored routine execution stack. The reason was in that there was no check if a new statement started at time of resetting. The artifact affects most of binlogable DML queries. Notice, that multi-update is wrapped up within bug@27716 fix, multi-delete bug@29136. Fixed with saving parent's statement flag of whether the statement modified non-transactional table, and unioning (merging) the value with that was gained in mysql_execute_command. Resettling thd->no_trans_update members into thd->transaction.`member`; Asserting code; Effectively the following properties are held. 1. At the end of a substatement thd->transaction.stmt.modified_non_trans_table reflects the fact if such a table got modified by the substatement. That also respects THD::really_abort_on_warnin() requirements. 2. Eventually thd->transaction.stmt.modified_non_trans_table will be computed as the union of the values of all invoked sub-statements. That fixes this bug#27417; Computing of thd->transaction.all.modified_non_trans_table is refined to base to the stmt's value for all the case including insert .. select statement which before the patch had an extra issue bug@28960. Minor issues are covered with mysql_load, mysql_delete, and binloggin of insert in to temp_table select. The supplied test verifies limitely, mostly asserts. The ultimate testing is defered for bug@13270, bug@23333.
This commit is contained in:
@ -149,7 +149,7 @@ static bool end_active_trans(THD *thd)
|
||||
if (ha_commit(thd))
|
||||
error=1;
|
||||
thd->options&= ~(ulong) OPTION_BEGIN;
|
||||
thd->no_trans_update.all= FALSE;
|
||||
thd->transaction.all.modified_non_trans_table= FALSE;
|
||||
}
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
@ -173,7 +173,7 @@ static bool begin_trans(THD *thd)
|
||||
else
|
||||
{
|
||||
LEX *lex= thd->lex;
|
||||
thd->no_trans_update.all= FALSE;
|
||||
thd->transaction.all.modified_non_trans_table= FALSE;
|
||||
thd->options|= (ulong) OPTION_BEGIN;
|
||||
thd->server_status|= SERVER_STATUS_IN_TRANS;
|
||||
if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
|
||||
@ -1471,7 +1471,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
|
||||
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
|
||||
res= ha_commit(thd);
|
||||
thd->options&= ~(ulong) OPTION_BEGIN;
|
||||
thd->no_trans_update.all= FALSE;
|
||||
thd->transaction.all.modified_non_trans_table= FALSE;
|
||||
break;
|
||||
case COMMIT_RELEASE:
|
||||
do_release= 1; /* fall through */
|
||||
@ -1489,7 +1489,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
|
||||
if (ha_rollback(thd))
|
||||
res= -1;
|
||||
thd->options&= ~(ulong) OPTION_BEGIN;
|
||||
thd->no_trans_update.all= FALSE;
|
||||
thd->transaction.all.modified_non_trans_table= FALSE;
|
||||
if (!res && (completion == ROLLBACK_AND_CHAIN))
|
||||
res= begin_trans(thd);
|
||||
break;
|
||||
@ -2600,6 +2600,8 @@ mysql_execute_command(THD *thd)
|
||||
statistic_increment(thd->status_var.com_stat[lex->sql_command],
|
||||
&LOCK_status);
|
||||
|
||||
DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table == FALSE);
|
||||
|
||||
switch (lex->sql_command) {
|
||||
case SQLCOM_SELECT:
|
||||
{
|
||||
@ -2937,7 +2939,7 @@ mysql_execute_command(THD *thd)
|
||||
else
|
||||
{
|
||||
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
|
||||
thd->no_trans_update.all= TRUE;
|
||||
thd->transaction.all.modified_non_trans_table= TRUE;
|
||||
}
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
bool link_to_local;
|
||||
@ -3720,7 +3722,7 @@ end_with_restore_list:
|
||||
lex->drop_if_exists= 1;
|
||||
|
||||
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
|
||||
thd->no_trans_update.all= TRUE;
|
||||
thd->transaction.all.modified_non_trans_table= TRUE;
|
||||
}
|
||||
/* DDL and binlog write order protected by LOCK_open */
|
||||
res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
|
||||
@ -4322,7 +4324,7 @@ end_with_restore_list:
|
||||
res= TRUE; // cannot happen
|
||||
else
|
||||
{
|
||||
if (thd->no_trans_update.all &&
|
||||
if (thd->transaction.all.modified_non_trans_table &&
|
||||
!thd->slave_thread)
|
||||
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||
ER_WARNING_NOT_COMPLETE_ROLLBACK,
|
||||
@ -4969,7 +4971,7 @@ create_sp_error:
|
||||
thd->transaction.xid_state.xa_state=XA_ACTIVE;
|
||||
thd->transaction.xid_state.xid.set(thd->lex->xid);
|
||||
xid_cache_insert(&thd->transaction.xid_state);
|
||||
thd->no_trans_update.all= FALSE;
|
||||
thd->transaction.all.modified_non_trans_table= FALSE;
|
||||
thd->options|= (ulong) OPTION_BEGIN;
|
||||
thd->server_status|= SERVER_STATUS_IN_TRANS;
|
||||
send_ok(thd);
|
||||
@ -5064,7 +5066,7 @@ create_sp_error:
|
||||
break;
|
||||
}
|
||||
thd->options&= ~(ulong) OPTION_BEGIN;
|
||||
thd->no_trans_update.all= FALSE;
|
||||
thd->transaction.all.modified_non_trans_table= FALSE;
|
||||
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
|
||||
xid_cache_delete(&thd->transaction.xid_state);
|
||||
thd->transaction.xid_state.xa_state=XA_NOTR;
|
||||
@ -5095,7 +5097,7 @@ create_sp_error:
|
||||
else
|
||||
send_ok(thd);
|
||||
thd->options&= ~(ulong) OPTION_BEGIN;
|
||||
thd->no_trans_update.all= FALSE;
|
||||
thd->transaction.all.modified_non_trans_table= FALSE;
|
||||
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
|
||||
xid_cache_delete(&thd->transaction.xid_state);
|
||||
thd->transaction.xid_state.xa_state=XA_NOTR;
|
||||
|
Reference in New Issue
Block a user