mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
Fix for bug #35732: read-only blocks SELECT statements in InnoDB
Problem: SELECTs prohibited for a transactional SE in autocommit mode if read_only is set. Fix: allow them. mysql-test/r/read_only_innodb.result: Fix for bug #35732: read-only blocks SELECT statements in InnoDB - test result. mysql-test/t/read_only_innodb.test: Fix for bug #35732: read-only blocks SELECT statements in InnoDB - test case. sql/handler.cc: Fix for bug #35732: read-only blocks SELECT statements in InnoDB - in autocommit mode thd->transaction.all list is empty thus is_real_trans set to TRUE for any SELECTs, so using it in the "read_only" check is insufficient. ha_check_and_coalesce_trx_read_only() changed to return number of engines with read-write changes. This value is used in the "read-only" check and checks for GLOBAL READ LOCK. sql/lock.cc: Fix for bug #35732: read-only blocks SELECT statements in InnoDB - added assert(protect_against_global_read_lock) before decreasing, in order to catch (uint) 0 - 1 situation due to wrong wait_if_global_read_lock()/start_waiting_global_read_lock() call sequence.
This commit is contained in:
@@ -952,16 +952,21 @@ int ha_prepare(THD *thd)
|
||||
A helper function to evaluate if two-phase commit is mandatory.
|
||||
As a side effect, propagates the read-only/read-write flags
|
||||
of the statement transaction to its enclosing normal transaction.
|
||||
|
||||
If we have at least two engines with read-write changes we must
|
||||
run a two-phase commit. Otherwise we can run several independent
|
||||
commits as the only transactional engine has read-write changes
|
||||
and others are read-only.
|
||||
|
||||
@retval TRUE we must run a two-phase commit. Returned
|
||||
if we have at least two engines with read-write changes.
|
||||
@retval FALSE Don't need two-phase commit. Even if we have two
|
||||
transactional engines, we can run two independent
|
||||
commits if changes in one of the engines are read-only.
|
||||
@retval 0 All engines are read-only.
|
||||
@retval 1 We have the only engine with read-write changes.
|
||||
@retval >1 More than one engine have read-write changes.
|
||||
Note: return value might NOT be the exact number of
|
||||
engines with read-write changes.
|
||||
*/
|
||||
|
||||
static
|
||||
bool
|
||||
uint
|
||||
ha_check_and_coalesce_trx_read_only(THD *thd, Ha_trx_info *ha_list,
|
||||
bool all)
|
||||
{
|
||||
@@ -998,7 +1003,7 @@ ha_check_and_coalesce_trx_read_only(THD *thd, Ha_trx_info *ha_list,
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rw_ha_count > 1;
|
||||
return rw_ha_count;
|
||||
}
|
||||
|
||||
|
||||
@@ -1061,25 +1066,8 @@ int ha_commit_trans(THD *thd, bool all)
|
||||
#ifdef USING_TRANSACTIONS
|
||||
if (ha_info)
|
||||
{
|
||||
bool must_2pc;
|
||||
|
||||
if (is_real_trans && wait_if_global_read_lock(thd, 0, 0))
|
||||
{
|
||||
ha_rollback_trans(thd, all);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
if ( is_real_trans
|
||||
&& opt_readonly
|
||||
&& ! (thd->security_ctx->master_access & SUPER_ACL)
|
||||
&& ! thd->slave_thread
|
||||
)
|
||||
{
|
||||
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
|
||||
ha_rollback_trans(thd, all);
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
uint rw_ha_count;
|
||||
bool rw_trans;
|
||||
|
||||
DBUG_EXECUTE_IF("crash_commit_before", abort(););
|
||||
|
||||
@@ -1087,9 +1075,29 @@ int ha_commit_trans(THD *thd, bool all)
|
||||
if (is_real_trans) /* not a statement commit */
|
||||
thd->stmt_map.close_transient_cursors();
|
||||
|
||||
must_2pc= ha_check_and_coalesce_trx_read_only(thd, ha_info, all);
|
||||
rw_ha_count= ha_check_and_coalesce_trx_read_only(thd, ha_info, all);
|
||||
/* rw_trans is TRUE when we in a transaction changing data */
|
||||
rw_trans= is_real_trans && (rw_ha_count > 0);
|
||||
|
||||
if (!trans->no_2pc && must_2pc)
|
||||
if (rw_trans &&
|
||||
wait_if_global_read_lock(thd, 0, 0))
|
||||
{
|
||||
ha_rollback_trans(thd, all);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
if (rw_trans &&
|
||||
opt_readonly &&
|
||||
!(thd->security_ctx->master_access & SUPER_ACL) &&
|
||||
!thd->slave_thread)
|
||||
{
|
||||
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
|
||||
ha_rollback_trans(thd, all);
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!trans->no_2pc && (rw_ha_count > 1))
|
||||
{
|
||||
for (; ha_info && !error; ha_info= ha_info->next())
|
||||
{
|
||||
@@ -1129,7 +1137,7 @@ int ha_commit_trans(THD *thd, bool all)
|
||||
tc_log->unlog(cookie, xid);
|
||||
DBUG_EXECUTE_IF("crash_commit_after", abort(););
|
||||
end:
|
||||
if (is_real_trans)
|
||||
if (rw_trans)
|
||||
start_waiting_global_read_lock(thd);
|
||||
}
|
||||
#endif /* USING_TRANSACTIONS */
|
||||
|
||||
Reference in New Issue
Block a user