Merge branch '10.6' into mariadb-10.6.20

This commit is contained in:
Oleksandr Byelkin 2024-11-04 07:40:45 +01:00
commit f2bb2ab58c
13 changed files with 223 additions and 84 deletions

View file

@ -1,4 +1,4 @@
MYSQL_VERSION_MAJOR=10
MYSQL_VERSION_MINOR=6
MYSQL_VERSION_PATCH=20
MYSQL_VERSION_PATCH=21
SERVER_MATURITY=stable

View file

@ -4340,3 +4340,16 @@ DROP TABLE t0;
#
# End of 10.5 tests
#
#
# Start of 10.6 tests
#
#
# MDEV-20944 Wrong result of LEAST() and ASAN heap-use-after-free in my_strnncollsp_simple / Item::temporal_precision on TIME()
#
SET NAMES latin1;
SELECT LEAST( CAST( 0 AS CHAR ), OLD_PASSWORD( 1 ) );
LEAST( CAST( 0 AS CHAR ), OLD_PASSWORD( 1 ) )
0
#
# End of 10.6 tests
#

View file

@ -1141,3 +1141,18 @@ DROP TABLE t0;
--echo #
--echo # End of 10.5 tests
--echo #
--echo #
--echo # Start of 10.6 tests
--echo #
--echo #
--echo # MDEV-20944 Wrong result of LEAST() and ASAN heap-use-after-free in my_strnncollsp_simple / Item::temporal_precision on TIME()
--echo #
SET NAMES latin1;
SELECT LEAST( CAST( 0 AS CHAR ), OLD_PASSWORD( 1 ) );
--echo #
--echo # End of 10.6 tests
--echo #

View file

@ -224,3 +224,8 @@ SELECT INTERVAL(1,ROW(1,2));
ERROR 21000: Operand should contain 1 column(s)
SELECT INTERVAL(ROW(1,2),1);
ERROR 21000: Operand should contain 1 column(s)
#
# MDEV-29184 Assertion `0' in Item_row::illegal_method_call, Type_handler_row::Item_update_null_value, Item::update_null_value
#
SELECT INTERVAL(0, ROW(1,1), 1, 1, 1, 1, 1, 1, 1) AS f;
ERROR 21000: Operand should contain 1 column(s)

View file

@ -147,3 +147,11 @@ SELECT INTERVAL(ROW(1,1),ROW(1,2));
SELECT INTERVAL(1,ROW(1,2));
--error ER_OPERAND_COLUMNS
SELECT INTERVAL(ROW(1,2),1);
--echo #
--echo # MDEV-29184 Assertion `0' in Item_row::illegal_method_call, Type_handler_row::Item_update_null_value, Item::update_null_value
--echo #
--error ER_OPERAND_COLUMNS
SELECT INTERVAL(0, ROW(1,1), 1, 1, 1, 1, 1, 1, 1) AS f;

View file

@ -0,0 +1,42 @@
include/master-slave.inc
[connection master]
connection master;
CREATE TABLE t (a INT) ENGINE = innodb;
connection slave;
include/stop_slave.inc
SET @old_parallel_threads= @@GLOBAL.slave_parallel_threads;
SET @old_parallel_mode = @@GLOBAL.slave_parallel_mode;
SET @@global.slave_parallel_threads= 2;
SET @@global.slave_parallel_mode = 'optimistic';
connection master;
# MDEV-35110
SET @@gtid_seq_no=100;
insert into t set a=1;
xa start 'x';
insert into t set a=2;
xa end 'x';
xa prepare 'x';
connection slave;
SET @@global.debug_dbug="+d,hold_worker_on_schedule";
start slave;
connection slave1;
backup stage start;
backup stage block_commit;
connection slave;
SET debug_sync = 'now SIGNAL continue_worker';
SET debug_sync = RESET;
connection slave1;
backup stage end;
connection master;
xa rollback 'x';
connection slave;
# Clean up.
connection slave;
include/stop_slave.inc
SET @@global.debug_dbug="";
SET @@global.slave_parallel_threads= @old_parallel_threads;
SET @@global.slave_parallel_mode = @old_parallel_mode;
include/start_slave.inc
connection server_1;
DROP TABLE t;
include/rpl_end.inc

View file

@ -0,0 +1,64 @@
# Verify deadlock between XA-PREPARE and BACKUP on the optimistic slave
--source include/have_debug.inc
--source include/have_debug_sync.inc
--source include/have_innodb.inc
# The test is not format specific, MIXED is required to optimize testing time
--source include/have_binlog_format_mixed.inc
--source include/master-slave.inc
--connection master
CREATE TABLE t (a INT) ENGINE = innodb;
--sync_slave_with_master
--source include/stop_slave.inc
SET @old_parallel_threads= @@GLOBAL.slave_parallel_threads;
SET @old_parallel_mode = @@GLOBAL.slave_parallel_mode;
SET @@global.slave_parallel_threads= 2;
SET @@global.slave_parallel_mode = 'optimistic';
--connection master
--echo # MDEV-35110
SET @@gtid_seq_no=100;
insert into t set a=1;
xa start 'x';
insert into t set a=2;
xa end 'x';
xa prepare 'x';
--connection slave
SET @@global.debug_dbug="+d,hold_worker_on_schedule";
start slave;
--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to commit"
--source include/wait_condition.inc
--connection slave1
backup stage start;
--send backup stage block_commit
--connection slave
--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state LIKE "Waiting for backup lock"
SET debug_sync = 'now SIGNAL continue_worker';
SET debug_sync = RESET;
--connection slave1
reap;
backup stage end;
--connection master
xa rollback 'x';
--sync_slave_with_master
--echo # Clean up.
--connection slave
--source include/stop_slave.inc
SET @@global.debug_dbug="";
SET @@global.slave_parallel_threads= @old_parallel_threads;
SET @@global.slave_parallel_mode = @old_parallel_mode;
--source include/start_slave.inc
--connection server_1
DROP TABLE t;
--source include/rpl_end.inc

View file

@ -1781,7 +1781,13 @@ int ha_commit_trans(THD *thd, bool all)
DBUG_PRINT("info", ("is_real_trans: %d rw_trans: %d rw_ha_count: %d",
is_real_trans, rw_trans, rw_ha_count));
if (rw_trans)
/*
backup_commit_lock may have already been set.
This can happen in case of spider that does xa_commit() by
calling ha_commit_trans() from spader_commit().
*/
if (rw_trans && !thd->backup_commit_lock)
{
/*
Acquire a metadata lock which will ensure that COMMIT is blocked
@ -2052,8 +2058,8 @@ end:
not needed.
*/
thd->mdl_context.release_lock(mdl_backup.ticket);
thd->backup_commit_lock= 0;
}
thd->backup_commit_lock= 0;
#ifdef WITH_WSREP
if (wsrep_is_active(thd) && is_real_trans && !error &&
(rw_ha_count == 0 || all) &&

View file

@ -1951,22 +1951,15 @@ bool Item_func_opt_neg::eq(const Item *item, bool binary_cmp) const
}
bool Item_func_interval::fix_fields(THD *thd, Item **ref)
bool Item_func_interval::fix_length_and_dec()
{
if (Item_long_func::fix_fields(thd, ref))
return true;
for (uint i= 0 ; i < row->cols(); i++)
uint rows= row->cols();
for (uint i= 0 ; i < rows; i++)
{
if (row->element_index(i)->check_cols(1))
return true;
}
return false;
}
bool Item_func_interval::fix_length_and_dec()
{
uint rows= row->cols();
use_decimal_comparison= ((row->element_index(0)->result_type() ==
DECIMAL_RESULT) ||

View file

@ -1120,7 +1120,6 @@ public:
Item_func_interval(THD *thd, Item_row *a):
Item_long_func(thd, a), row(a), intervals(0)
{ }
bool fix_fields(THD *, Item **) override;
longlong val_int() override;
bool fix_length_and_dec() override;
LEX_CSTRING func_name_cstring() const override

View file

@ -2987,13 +2987,15 @@ String *Item_func_min_max::val_str_native(String *str)
res=args[i]->val_str(str);
else
{
String *res2;
res2= args[i]->val_str(res == str ? &tmp_value : str);
String *res2= args[i]->val_str(&tmp_value);
if (res2)
{
int cmp= sortcmp(res,res2,collation.collation);
if ((cmp_sign < 0 ? cmp : -cmp) < 0)
res=res2;
{
str->copy(*res2);
res= str;
}
}
}
if ((null_value= args[i]->null_value))

120
sql/xa.cc
View file

@ -507,6 +507,40 @@ bool trans_xa_end(THD *thd)
}
/*
Get the BACKUP_COMMIT lock for the duration of the XA.
The metadata lock which will ensure that COMMIT is blocked
by active FLUSH TABLES WITH READ LOCK (and vice versa COMMIT in
progress blocks FTWRL) and also by MDL_BACKUP_WAIT_COMMIT.
We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
Note that the function sets thd->backup_lock on sucess. The caller needs
to reset thd->backup_commit_lock before returning!
*/
static bool trans_xa_get_backup_lock(THD *thd, MDL_request *mdl_request)
{
DBUG_ASSERT(thd->backup_commit_lock == 0);
MDL_REQUEST_INIT(mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
MDL_EXPLICIT);
if (thd->mdl_context.acquire_lock(mdl_request,
thd->variables.lock_wait_timeout))
return 1;
thd->backup_commit_lock= mdl_request;
return 0;
}
static inline void trans_xa_release_backup_lock(THD *thd)
{
if (thd->backup_commit_lock)
{
thd->mdl_context.release_lock(thd->backup_commit_lock->ticket);
thd->backup_commit_lock= 0;
}
}
/**
Put a XA transaction in the PREPARED state.
@ -529,22 +563,15 @@ bool trans_xa_prepare(THD *thd)
my_error(ER_XAER_NOTA, MYF(0));
else
{
/*
Acquire metadata lock which will ensure that COMMIT is blocked
by active FLUSH TABLES WITH READ LOCK (and vice versa COMMIT in
progress blocks FTWRL).
We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
*/
MDL_request mdl_request;
MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
MDL_STATEMENT);
if (thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout) ||
if (trans_xa_get_backup_lock(thd, &mdl_request) ||
ha_prepare(thd))
{
if (!mdl_request.ticket)
{
/* Failed to get the backup lock */
ha_rollback_trans(thd, TRUE);
}
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction->all.reset();
thd->server_status&=
@ -572,6 +599,7 @@ bool trans_xa_prepare(THD *thd)
res= thd->variables.pseudo_slave_mode || thd->slave_thread ?
slave_applier_reset_xa_trans(thd) : 0;
}
trans_xa_release_backup_lock(thd);
}
DBUG_RETURN(res);
@ -635,19 +663,8 @@ bool trans_xa_commit(THD *thd)
res= 1;
goto _end_external_xid;
}
res= xa_trans_rolled_back(xs);
/*
Acquire metadata lock which will ensure that COMMIT is blocked
by active FLUSH TABLES WITH READ LOCK (and vice versa COMMIT in
progress blocks FTWRL).
We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
*/
MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
MDL_EXPLICIT);
if (thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout))
if (trans_xa_get_backup_lock(thd, &mdl_request))
{
/*
We can't rollback an XA transaction on lock failure due to
@ -659,14 +676,11 @@ bool trans_xa_commit(THD *thd)
res= true;
goto _end_external_xid;
}
else
{
thd->backup_commit_lock= &mdl_request;
}
DBUG_ASSERT(!xid_state.xid_cache_element);
xid_state.xid_cache_element= xs;
ha_commit_or_rollback_by_xid(thd->lex->xid, !res);
if (!res && thd->is_error())
{
// hton completion error retains xs/xid in the cache,
@ -682,11 +696,7 @@ bool trans_xa_commit(THD *thd)
res= res || thd->is_error();
if (!xid_deleted)
xs->acquired_to_recovered();
if (mdl_request.ticket)
{
thd->mdl_context.release_lock(mdl_request.ticket);
thd->backup_commit_lock= 0;
}
trans_xa_release_backup_lock(thd);
}
else
my_error(ER_XAER_NOTA, MYF(0));
@ -709,7 +719,8 @@ bool trans_xa_commit(THD *thd)
if ((res= MY_TEST(r)))
my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
}
else if (thd->transaction->xid_state.xid_cache_element->xa_state == XA_PREPARED)
else if (thd->transaction->xid_state.xid_cache_element->xa_state ==
XA_PREPARED)
{
MDL_request mdl_request;
if (thd->lex->xa_opt != XA_NONE)
@ -718,18 +729,7 @@ bool trans_xa_commit(THD *thd)
DBUG_RETURN(TRUE);
}
/*
Acquire metadata lock which will ensure that COMMIT is blocked
by active FLUSH TABLES WITH READ LOCK (and vice versa COMMIT in
progress blocks FTWRL).
We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
*/
MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
MDL_TRANSACTION);
if (thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout))
if (trans_xa_get_backup_lock(thd, &mdl_request))
{
/*
We can't rollback an XA transaction on lock failure due to
@ -756,6 +756,7 @@ bool trans_xa_commit(THD *thd)
}
thd->m_transaction_psi= NULL;
trans_xa_release_backup_lock(thd);
}
}
else
@ -793,7 +794,8 @@ bool trans_xa_commit(THD *thd)
bool trans_xa_rollback(THD *thd)
{
XID_STATE &xid_state= thd->transaction->xid_state;
MDL_request mdl_request;
bool error;
DBUG_ENTER("trans_xa_rollback");
if (!xid_state.is_explicit_XA() ||
@ -814,7 +816,6 @@ bool trans_xa_rollback(THD *thd)
{
bool res;
bool xid_deleted= false;
MDL_request mdl_request;
bool rw_trans= (xs->rm_error != ER_XA_RBROLLBACK);
if (rw_trans && thd->is_read_only_ctx())
@ -824,10 +825,7 @@ bool trans_xa_rollback(THD *thd)
goto _end_external_xid;
}
MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
MDL_EXPLICIT);
if (thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout))
if (trans_xa_get_backup_lock(thd, &mdl_request))
{
/*
We can't rollback an XA transaction on lock failure due to
@ -838,10 +836,6 @@ bool trans_xa_rollback(THD *thd)
goto _end_external_xid;
}
else
{
thd->backup_commit_lock= &mdl_request;
}
res= xa_trans_rolled_back(xs);
DBUG_ASSERT(!xid_state.xid_cache_element);
@ -858,11 +852,7 @@ bool trans_xa_rollback(THD *thd)
xid_state.xid_cache_element= 0;
if (!xid_deleted)
xs->acquired_to_recovered();
if (mdl_request.ticket)
{
thd->mdl_context.release_lock(mdl_request.ticket);
thd->backup_commit_lock= 0;
}
trans_xa_release_backup_lock(thd);
}
else
my_error(ER_XAER_NOTA, MYF(0));
@ -879,11 +869,7 @@ bool trans_xa_rollback(THD *thd)
DBUG_RETURN(TRUE);
}
MDL_request mdl_request;
MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
MDL_STATEMENT);
if (thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout))
if (trans_xa_get_backup_lock(thd, &mdl_request))
{
/*
We can't rollback an XA transaction on lock failure due to
@ -894,7 +880,9 @@ bool trans_xa_rollback(THD *thd)
DBUG_RETURN(true);
}
DBUG_RETURN(xa_trans_force_rollback(thd));
error= xa_trans_force_rollback(thd);
trans_xa_release_backup_lock(thd);
DBUG_RETURN(error);
}

View file

@ -402,6 +402,10 @@ row_vers_impl_x_locked(
const rec_t* clust_rec;
dict_index_t* clust_index;
/* The function must not be invoked under lock_sys latch to prevert
latching orded violation, i.e. page latch must be acquired before
lock_sys latch */
lock_sys.assert_unlocked();
/* The current function can be called from lock_rec_unlock_unmodified()
under lock_sys.wr_lock() */