mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-19491 update query stopped working after mariadb upgrade 10.2.23 -> 10.2.24
as well as
MDEV-19500 Update with join stopped worked if there is a call to a procedure in a trigger
MDEV-19521 Update Table Fails with Trigger and Stored Function
MDEV-19497 Replication stops because table not found
MDEV-19527 UPDATE + JOIN + TRIGGERS = table doesn't exists error
Reimplement the fix for (5d510fdbf0
)
MDEV-18507 can't update temporary table when joined with table with triggers on read-only
instead of calling open_tables() twice, put multi-update
prepare code inside open_tables() loop.
Add a test for a MDL backoff-and-retry loop inside open_tables()
across multi-update prepare code.
This commit is contained in:
@@ -1038,6 +1038,24 @@ triggered
|
|||||||
triggered
|
triggered
|
||||||
drop table t1,t2, t3;
|
drop table t1,t2, t3;
|
||||||
drop user foo;
|
drop user foo;
|
||||||
|
create table t1 (a int, b int);
|
||||||
|
create table t2 (c int, d int);
|
||||||
|
insert t1 values (1,2),(3,4);
|
||||||
|
insert t2 values (5,6),(7,8);
|
||||||
|
create table t0 (x int);
|
||||||
|
insert t0 values (11), (22);
|
||||||
|
create trigger tr1 before update on t2 for each row insert t0 values (new.c);
|
||||||
|
lock table t0 write;
|
||||||
|
update t1 join t2 on (a=c+4) set b=d;
|
||||||
|
drop table t1, t2, t0;
|
||||||
|
create table t1 (a int, b varchar(50), c varchar(50));
|
||||||
|
insert t1 (a,b) values (1,'1'), (2,'2'), (3,'3');
|
||||||
|
create function f1() returns varchar(50) return 'result';
|
||||||
|
create trigger tr before update on t1 for each row set new.c = (select f1());
|
||||||
|
create table t2 select a, b from t1;
|
||||||
|
update t1 join t2 using (a) set t1.b = t2.b;
|
||||||
|
drop table t1, t2;
|
||||||
|
drop function f1;
|
||||||
#
|
#
|
||||||
# end of 5.5 tests
|
# end of 5.5 tests
|
||||||
#
|
#
|
||||||
|
13
mysql-test/r/multi_update_debug.result
Normal file
13
mysql-test/r/multi_update_debug.result
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
create table t1 (a int, b int);
|
||||||
|
create table t2 (c int, d int);
|
||||||
|
insert t1 values (1,2),(3,4);
|
||||||
|
insert t2 values (5,6),(7,8);
|
||||||
|
create table t0 (x int);
|
||||||
|
insert t0 values (11), (22);
|
||||||
|
create trigger tr1 before update on t1 for each row insert t0 values (new.b);
|
||||||
|
set debug_sync='open_tables_after_open_and_process_table WAIT_FOR cont';
|
||||||
|
update t1 join t2 on (a=c+4) set b=d;
|
||||||
|
set debug_sync='mdl_acquire_lock_wait SIGNAL cont';
|
||||||
|
lock table t1 write, t0 write;
|
||||||
|
drop table t1, t2, t0;
|
||||||
|
set debug_sync='reset';
|
@@ -67,6 +67,20 @@ SELECT * FROM t2;
|
|||||||
col_int_key pk_1 pk_2 col_int
|
col_int_key pk_1 pk_2 col_int
|
||||||
1 2 3 4
|
1 2 3 4
|
||||||
DROP TABLE t1,t2;
|
DROP TABLE t1,t2;
|
||||||
|
create table t1 (id serial, size int(11)) engine=innodb;
|
||||||
|
create table t2 (id serial, size int, account_id int) engine=innodb;
|
||||||
|
create table t3 (id serial, size int, article_id int) engine=innodb;
|
||||||
|
create table t4 (id serial, file_id int, article_id int) engine=innodb;
|
||||||
|
insert t1 values(null, 400);
|
||||||
|
insert t2 values(null, 0, 1), (null, 1, 1);
|
||||||
|
insert t3 values(null, 100, 1);
|
||||||
|
insert t4 values(null, 1, 2);
|
||||||
|
create trigger file_update_article before update on t3 for each row
|
||||||
|
update t2 set t2.size = new.size where t2.id = new.article_id;
|
||||||
|
create trigger article_update_account before update on t2 for each row
|
||||||
|
update t1 set t1.size = t1.size + new.size where t1.id = new.account_id;
|
||||||
|
update t3 join t4 on t4.file_id =t3.id and t4.article_id=2 set t3.size=t3.size + 2;
|
||||||
|
drop table t1, t2, t3, t4;
|
||||||
#
|
#
|
||||||
# end of 5.5 tests
|
# end of 5.5 tests
|
||||||
#
|
#
|
||||||
|
@@ -1081,6 +1081,35 @@ select * from t2;
|
|||||||
drop table t1,t2, t3;
|
drop table t1,t2, t3;
|
||||||
drop user foo;
|
drop user foo;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Another test on not-opening tables unnecessary
|
||||||
|
#
|
||||||
|
create table t1 (a int, b int);
|
||||||
|
create table t2 (c int, d int);
|
||||||
|
insert t1 values (1,2),(3,4);
|
||||||
|
insert t2 values (5,6),(7,8);
|
||||||
|
create table t0 (x int);
|
||||||
|
insert t0 values (11), (22);
|
||||||
|
create trigger tr1 before update on t2 for each row insert t0 values (new.c);
|
||||||
|
connect con1, localhost, root;
|
||||||
|
lock table t0 write;
|
||||||
|
connection default;
|
||||||
|
update t1 join t2 on (a=c+4) set b=d;
|
||||||
|
disconnect con1;
|
||||||
|
drop table t1, t2, t0;
|
||||||
|
|
||||||
|
#
|
||||||
|
# MDEV-19521 Update Table Fails with Trigger and Stored Function
|
||||||
|
#
|
||||||
|
create table t1 (a int, b varchar(50), c varchar(50));
|
||||||
|
insert t1 (a,b) values (1,'1'), (2,'2'), (3,'3');
|
||||||
|
create function f1() returns varchar(50) return 'result';
|
||||||
|
create trigger tr before update on t1 for each row set new.c = (select f1());
|
||||||
|
create table t2 select a, b from t1;
|
||||||
|
update t1 join t2 using (a) set t1.b = t2.b;
|
||||||
|
drop table t1, t2;
|
||||||
|
drop function f1;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # end of 5.5 tests
|
--echo # end of 5.5 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
27
mysql-test/t/multi_update_debug.test
Normal file
27
mysql-test/t/multi_update_debug.test
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#
|
||||||
|
# test MDL backoff-and-retry during multi-update
|
||||||
|
#
|
||||||
|
source include/have_debug_sync.inc;
|
||||||
|
create table t1 (a int, b int);
|
||||||
|
create table t2 (c int, d int);
|
||||||
|
insert t1 values (1,2),(3,4);
|
||||||
|
insert t2 values (5,6),(7,8);
|
||||||
|
create table t0 (x int);
|
||||||
|
insert t0 values (11), (22);
|
||||||
|
create trigger tr1 before update on t1 for each row insert t0 values (new.b);
|
||||||
|
|
||||||
|
set debug_sync='open_tables_after_open_and_process_table WAIT_FOR cont';
|
||||||
|
send update t1 join t2 on (a=c+4) set b=d;
|
||||||
|
|
||||||
|
connect con1, localhost, root;
|
||||||
|
let $wait_condition= select count(*) from information_schema.processlist where state = ' debug sync point: open_tables_after_open_and_process_table'
|
||||||
|
source include/wait_condition.inc;
|
||||||
|
set debug_sync='mdl_acquire_lock_wait SIGNAL cont';
|
||||||
|
lock table t1 write, t0 write;
|
||||||
|
let $wait_condition= select count(*) from information_schema.processlist where state = 'Waiting for table metadata lock'
|
||||||
|
source include/wait_condition.inc;
|
||||||
|
disconnect con1;
|
||||||
|
connection default;
|
||||||
|
reap;
|
||||||
|
drop table t1, t2, t0;
|
||||||
|
set debug_sync='reset';
|
@@ -76,6 +76,24 @@ SELECT * FROM t2;
|
|||||||
|
|
||||||
DROP TABLE t1,t2;
|
DROP TABLE t1,t2;
|
||||||
|
|
||||||
|
#
|
||||||
|
# MDEV-19491 update query stopped working after mariadb upgrade 10.2.23 -> 10.2.24
|
||||||
|
#
|
||||||
|
create table t1 (id serial, size int(11)) engine=innodb;
|
||||||
|
create table t2 (id serial, size int, account_id int) engine=innodb;
|
||||||
|
create table t3 (id serial, size int, article_id int) engine=innodb;
|
||||||
|
create table t4 (id serial, file_id int, article_id int) engine=innodb;
|
||||||
|
insert t1 values(null, 400);
|
||||||
|
insert t2 values(null, 0, 1), (null, 1, 1);
|
||||||
|
insert t3 values(null, 100, 1);
|
||||||
|
insert t4 values(null, 1, 2);
|
||||||
|
create trigger file_update_article before update on t3 for each row
|
||||||
|
update t2 set t2.size = new.size where t2.id = new.article_id;
|
||||||
|
create trigger article_update_account before update on t2 for each row
|
||||||
|
update t1 set t1.size = t1.size + new.size where t1.id = new.account_id;
|
||||||
|
update t3 join t4 on t4.file_id =t3.id and t4.article_id=2 set t3.size=t3.size + 2;
|
||||||
|
drop table t1, t2, t3, t4;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # end of 5.5 tests
|
--echo # end of 5.5 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
@@ -5055,6 +5055,7 @@ restart:
|
|||||||
sroutine_to_open= &thd->lex->sroutines_list.first;
|
sroutine_to_open= &thd->lex->sroutines_list.first;
|
||||||
*counter= 0;
|
*counter= 0;
|
||||||
thd_proc_info(thd, "Opening tables");
|
thd_proc_info(thd, "Opening tables");
|
||||||
|
prelocking_strategy->reset(thd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If we are executing LOCK TABLES statement or a DDL statement
|
If we are executing LOCK TABLES statement or a DDL statement
|
||||||
@@ -5218,6 +5219,8 @@ restart:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ((error= prelocking_strategy->handle_end(thd)))
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -426,6 +426,7 @@ class Prelocking_strategy
|
|||||||
public:
|
public:
|
||||||
virtual ~Prelocking_strategy() { }
|
virtual ~Prelocking_strategy() { }
|
||||||
|
|
||||||
|
virtual void reset(THD *thd) { };
|
||||||
virtual bool handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
|
virtual bool handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
|
||||||
Sroutine_hash_entry *rt, sp_head *sp,
|
Sroutine_hash_entry *rt, sp_head *sp,
|
||||||
bool *need_prelocking) = 0;
|
bool *need_prelocking) = 0;
|
||||||
@@ -433,6 +434,7 @@ public:
|
|||||||
TABLE_LIST *table_list, bool *need_prelocking) = 0;
|
TABLE_LIST *table_list, bool *need_prelocking) = 0;
|
||||||
virtual bool handle_view(THD *thd, Query_tables_list *prelocking_ctx,
|
virtual bool handle_view(THD *thd, Query_tables_list *prelocking_ctx,
|
||||||
TABLE_LIST *table_list, bool *need_prelocking)= 0;
|
TABLE_LIST *table_list, bool *need_prelocking)= 0;
|
||||||
|
virtual bool handle_end(THD *thd) { return 0; };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1188,103 +1188,81 @@ bool unsafe_key_update(List<TABLE_LIST> leaves, table_map tables_for_update)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
class Multiupdate_prelocking_strategy : public DML_prelocking_strategy
|
||||||
make update specific preparation and checks after opening tables
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
mysql_multi_update_prepare()
|
|
||||||
thd thread handler
|
|
||||||
|
|
||||||
RETURN
|
|
||||||
FALSE OK
|
|
||||||
TRUE Error
|
|
||||||
*/
|
|
||||||
|
|
||||||
int mysql_multi_update_prepare(THD *thd)
|
|
||||||
{
|
{
|
||||||
|
bool done;
|
||||||
|
bool has_prelocking_list;
|
||||||
|
public:
|
||||||
|
void reset(THD *thd);
|
||||||
|
bool handle_end(THD *thd);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Multiupdate_prelocking_strategy::reset(THD *thd)
|
||||||
|
{
|
||||||
|
done= false;
|
||||||
|
has_prelocking_list= thd->lex->requires_prelocking();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Determine what tables could be updated in the multi-update
|
||||||
|
|
||||||
|
For these tables we'll need to open triggers and continue prelocking
|
||||||
|
until all is open.
|
||||||
|
*/
|
||||||
|
bool Multiupdate_prelocking_strategy::handle_end(THD *thd)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("Multiupdate_prelocking_strategy::handle_end");
|
||||||
|
if (done)
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
LEX *lex= thd->lex;
|
LEX *lex= thd->lex;
|
||||||
TABLE_LIST *table_list= lex->query_tables;
|
SELECT_LEX *select_lex= &lex->select_lex;
|
||||||
TABLE_LIST *tl;
|
TABLE_LIST *table_list= lex->query_tables, *tl;
|
||||||
List<Item> *fields= &lex->select_lex.item_list;
|
|
||||||
table_map tables_for_update;
|
|
||||||
bool update_view= 0;
|
|
||||||
DML_prelocking_strategy prelocking_strategy;
|
|
||||||
bool has_prelocking_list= thd->lex->requires_prelocking();
|
|
||||||
|
|
||||||
/*
|
done= true;
|
||||||
if this multi-update was converted from usual update, here is table
|
|
||||||
counter else junk will be assigned here, but then replaced with real
|
|
||||||
count in open_tables()
|
|
||||||
*/
|
|
||||||
uint table_count= lex->table_count;
|
|
||||||
const bool using_lock_tables= thd->locked_tables_mode != LTM_NONE;
|
|
||||||
bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI);
|
|
||||||
DBUG_ENTER("mysql_multi_update_prepare");
|
|
||||||
|
|
||||||
/* following need for prepared statements, to run next time multi-update */
|
if (mysql_handle_derived(lex, DT_INIT) ||
|
||||||
thd->lex->sql_command= SQLCOM_UPDATE_MULTI;
|
mysql_handle_derived(lex, DT_MERGE_FOR_INSERT) ||
|
||||||
|
mysql_handle_derived(lex, DT_PREPARE))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
/*
|
|
||||||
Open tables and create derived ones, but do not lock and fill them yet.
|
|
||||||
|
|
||||||
During prepare phase acquire only S metadata locks instead of SW locks to
|
|
||||||
keep prepare of multi-UPDATE compatible with concurrent LOCK TABLES WRITE
|
|
||||||
and global read lock.
|
|
||||||
*/
|
|
||||||
if ((original_multiupdate && open_tables(thd, &table_list, &table_count,
|
|
||||||
thd->stmt_arena->is_stmt_prepare()
|
|
||||||
? MYSQL_OPEN_FORCE_SHARED_MDL : 0,
|
|
||||||
&prelocking_strategy)) ||
|
|
||||||
mysql_handle_derived(lex, DT_INIT))
|
|
||||||
DBUG_RETURN(TRUE);
|
|
||||||
/*
|
/*
|
||||||
setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables()
|
setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables()
|
||||||
second time, but this call will do nothing (there are check for second
|
second time, but this call will do nothing (there are check for second
|
||||||
call in setup_tables()).
|
call in setup_tables()).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//We need to merge for insert prior to prepare.
|
if (setup_tables_and_check_access(thd, &select_lex->context,
|
||||||
if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT))
|
&select_lex->top_join_list, table_list, select_lex->leaf_tables,
|
||||||
DBUG_RETURN(TRUE);
|
|
||||||
if (mysql_handle_derived(lex, DT_PREPARE))
|
|
||||||
DBUG_RETURN(TRUE);
|
|
||||||
|
|
||||||
if (setup_tables_and_check_access(thd, &lex->select_lex.context,
|
|
||||||
&lex->select_lex.top_join_list,
|
|
||||||
table_list, lex->select_lex.leaf_tables,
|
|
||||||
FALSE, UPDATE_ACL, SELECT_ACL, FALSE))
|
FALSE, UPDATE_ACL, SELECT_ACL, FALSE))
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
if (lex->select_lex.handle_derived(thd->lex, DT_MERGE))
|
if (select_lex->handle_derived(thd->lex, DT_MERGE))
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
List<Item> *fields= &lex->select_lex.item_list;
|
||||||
if (setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0))
|
if (setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0))
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
for (tl= table_list; tl ; tl= tl->next_local)
|
for (tl= table_list; tl ; tl= tl->next_local)
|
||||||
{
|
|
||||||
if (tl->view)
|
if (tl->view)
|
||||||
{
|
{
|
||||||
update_view= 1;
|
if (check_fields(thd, *fields))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (update_view && check_fields(thd, *fields))
|
table_map tables_for_update= thd->table_map_for_update= get_table_map(fields);
|
||||||
DBUG_RETURN(TRUE);
|
|
||||||
|
|
||||||
thd->table_map_for_update= tables_for_update= get_table_map(fields);
|
if (unsafe_key_update(select_lex->leaf_tables, tables_for_update))
|
||||||
|
DBUG_RETURN(1);
|
||||||
if (unsafe_key_update(lex->select_lex.leaf_tables, tables_for_update))
|
|
||||||
DBUG_RETURN(true);
|
|
||||||
|
|
||||||
TABLE_LIST **new_tables= lex->query_tables_last;
|
|
||||||
DBUG_ASSERT(*new_tables== NULL);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Setup timestamp handling and locking mode
|
Setup timestamp handling and locking mode
|
||||||
*/
|
*/
|
||||||
List_iterator<TABLE_LIST> ti(lex->select_lex.leaf_tables);
|
List_iterator<TABLE_LIST> ti(select_lex->leaf_tables);
|
||||||
|
const bool using_lock_tables= thd->locked_tables_mode != LTM_NONE;
|
||||||
while ((tl= ti++))
|
while ((tl= ti++))
|
||||||
{
|
{
|
||||||
TABLE *table= tl->table;
|
TABLE *table= tl->table;
|
||||||
@@ -1299,7 +1277,7 @@ int mysql_multi_update_prepare(THD *thd)
|
|||||||
if (!tl->single_table_updatable() || check_key_in_view(thd, tl))
|
if (!tl->single_table_updatable() || check_key_in_view(thd, tl))
|
||||||
{
|
{
|
||||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), tl->alias, "UPDATE");
|
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), tl->alias, "UPDATE");
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_PRINT("info",("setting table `%s` for update", tl->alias));
|
DBUG_PRINT("info",("setting table `%s` for update", tl->alias));
|
||||||
@@ -1310,8 +1288,8 @@ int mysql_multi_update_prepare(THD *thd)
|
|||||||
tl->updating= 1;
|
tl->updating= 1;
|
||||||
if (tl->belong_to_view)
|
if (tl->belong_to_view)
|
||||||
tl->belong_to_view->updating= 1;
|
tl->belong_to_view->updating= 1;
|
||||||
if (extend_table_list(thd, tl, &prelocking_strategy, has_prelocking_list))
|
if (extend_table_list(thd, tl, this, has_prelocking_list))
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1333,17 +1311,64 @@ int mysql_multi_update_prepare(THD *thd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint addon_table_count= 0;
|
/* check single table update for view compound from several tables */
|
||||||
if (*new_tables)
|
for (tl= table_list; tl; tl= tl->next_local)
|
||||||
{
|
{
|
||||||
Sroutine_hash_entry **new_routines= thd->lex->sroutines_list.next;
|
TABLE_LIST *for_update= 0;
|
||||||
DBUG_ASSERT(*new_routines == NULL);
|
if (tl->is_merged_derived() &&
|
||||||
if (open_tables(thd, new_tables, &addon_table_count, new_routines,
|
tl->check_single_table(&for_update, tables_for_update, tl))
|
||||||
thd->stmt_arena->is_stmt_prepare()
|
{
|
||||||
? MYSQL_OPEN_FORCE_SHARED_MDL : 0,
|
my_error(ER_VIEW_MULTIUPDATE, MYF(0), tl->view_db.str, tl->view_name.str);
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
make update specific preparation and checks after opening tables
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
mysql_multi_update_prepare()
|
||||||
|
thd thread handler
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
FALSE OK
|
||||||
|
TRUE Error
|
||||||
|
*/
|
||||||
|
|
||||||
|
int mysql_multi_update_prepare(THD *thd)
|
||||||
|
{
|
||||||
|
LEX *lex= thd->lex;
|
||||||
|
TABLE_LIST *table_list= lex->query_tables;
|
||||||
|
TABLE_LIST *tl;
|
||||||
|
Multiupdate_prelocking_strategy prelocking_strategy;
|
||||||
|
uint table_count= lex->table_count;
|
||||||
|
DBUG_ENTER("mysql_multi_update_prepare");
|
||||||
|
|
||||||
|
/*
|
||||||
|
Open tables and create derived ones, but do not lock and fill them yet.
|
||||||
|
|
||||||
|
During prepare phase acquire only S metadata locks instead of SW locks to
|
||||||
|
keep prepare of multi-UPDATE compatible with concurrent LOCK TABLES WRITE
|
||||||
|
and global read lock.
|
||||||
|
*/
|
||||||
|
if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI)
|
||||||
|
{
|
||||||
|
if (open_tables(thd, &table_list, &table_count,
|
||||||
|
thd->stmt_arena->is_stmt_prepare() ? MYSQL_OPEN_FORCE_SHARED_MDL : 0,
|
||||||
&prelocking_strategy))
|
&prelocking_strategy))
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* following need for prepared statements, to run next time multi-update */
|
||||||
|
thd->lex->sql_command= SQLCOM_UPDATE_MULTI;
|
||||||
|
prelocking_strategy.reset(thd);
|
||||||
|
if (prelocking_strategy.handle_end(thd))
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
for (tl= table_list; tl; tl= tl->next_local)
|
for (tl= table_list; tl; tl= tl->next_local)
|
||||||
{
|
{
|
||||||
@@ -1358,24 +1383,9 @@ int mysql_multi_update_prepare(THD *thd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check single table update for view compound from several tables */
|
|
||||||
for (tl= table_list; tl; tl= tl->next_local)
|
|
||||||
{
|
|
||||||
if (tl->is_merged_derived())
|
|
||||||
{
|
|
||||||
TABLE_LIST *for_update= 0;
|
|
||||||
if (tl->check_single_table(&for_update, tables_for_update, tl))
|
|
||||||
{
|
|
||||||
my_error(ER_VIEW_MULTIUPDATE, MYF(0),
|
|
||||||
tl->view_db.str, tl->view_name.str);
|
|
||||||
DBUG_RETURN(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now lock and fill tables */
|
/* now lock and fill tables */
|
||||||
if (!thd->stmt_arena->is_stmt_prepare() &&
|
if (!thd->stmt_arena->is_stmt_prepare() &&
|
||||||
lock_tables(thd, table_list, table_count + addon_table_count, 0))
|
lock_tables(thd, table_list, table_count, 0))
|
||||||
{
|
{
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
@@ -1387,7 +1397,7 @@ int mysql_multi_update_prepare(THD *thd)
|
|||||||
*/
|
*/
|
||||||
lex->select_lex.exclude_from_table_unique_test= TRUE;
|
lex->select_lex.exclude_from_table_unique_test= TRUE;
|
||||||
/* We only need SELECT privilege for columns in the values list */
|
/* We only need SELECT privilege for columns in the values list */
|
||||||
ti.rewind();
|
List_iterator<TABLE_LIST> ti(lex->select_lex.leaf_tables);
|
||||||
while ((tl= ti++))
|
while ((tl= ti++))
|
||||||
{
|
{
|
||||||
TABLE *table= tl->table;
|
TABLE *table= tl->table;
|
||||||
|
Reference in New Issue
Block a user