Skip to content

Commit 516f68a

Browse files
committed
MDEV-37345 sequences and prelocking
if a bunch of tables are prelocked, when a table is actually needed in the routine, open_tables picks one table out of the prelocked list with a smallest "distance". Distance is simply a difference between the actual table lock and the requested table lock. Say, if the prelocked set contains both t1 write-locked and t1 read-locked, than an UPDATE will prefer write-locked t1 and SELECT will prefer read-locked. if there's only write-locked table in the set, both UPDATE and SELECT will use it. this doesn't distingush between UPDATE and INSERT, but INSERT marks tables with tables->for_insert_data=1, which causes prelocking to invoke add_internal_tables() and prepare sequences for execution. in this bug there were two prelocked t1's, one for INSERT (with for_insert_data=1) and one for UPDATE. INSERT picks the second (they both are write-locked, so the distance is the same), its sequence is not prepared and crashes. Let's add for_insert_data as the lowest bit into the distance.
1 parent 2bf1d08 commit 516f68a

File tree

3 files changed

+48
-1
lines changed

3 files changed

+48
-1
lines changed

mysql-test/suite/sql_sequence/other.result

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,4 +394,20 @@ create table t (id bigint default(nextval(s))) engine=myisam;
394394
insert delayed into t () values();
395395
drop table t;
396396
drop sequence s;
397+
#
398+
# MDEV-37345 Item_func_nextval::val_int() crash on INSERT...SELECT with subqueries
399+
#
400+
create sequence s;
401+
create table t1 (a int, b int default(nextval(s)));
402+
insert into t1 () values ();
403+
create table t2 (c int);
404+
create procedure p() update t1 set a = 0;
405+
create trigger tr after insert on t2 for each row
406+
begin
407+
insert into t1 () values ();
408+
call p();
409+
end $
410+
insert into t2 values ();
411+
drop table t1, t2, s;
412+
drop procedure p;
397413
# End of 10.11 tests

mysql-test/suite/sql_sequence/other.test

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,4 +428,24 @@ insert delayed into t () values();
428428
drop table t;
429429
drop sequence s;
430430

431+
--echo #
432+
--echo # MDEV-37345 Item_func_nextval::val_int() crash on INSERT...SELECT with subqueries
433+
--echo #
434+
# sequence and prelocking.
435+
create sequence s;
436+
create table t1 (a int, b int default(nextval(s)));
437+
insert into t1 () values ();
438+
create table t2 (c int);
439+
create procedure p() update t1 set a = 0;
440+
--delimiter $
441+
create trigger tr after insert on t2 for each row
442+
begin
443+
insert into t1 () values ();
444+
call p();
445+
end $
446+
--delimiter ;
447+
insert into t2 values ();
448+
drop table t1, t2, s;
449+
drop procedure p;
450+
431451
--echo # End of 10.11 tests

sql/sql_base.cc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2010,7 +2010,18 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
20102010
table->query_id == 0))
20112011
{
20122012
int distance= ((int) table->reginfo.lock_type -
2013-
(int) table_list->lock_type);
2013+
(int) table_list->lock_type) * 2;
2014+
TABLE_LIST *tl= thd->locked_tables_mode == LTM_PRELOCKED
2015+
? table->pos_in_table_list : table->pos_in_locked_tables;
2016+
/*
2017+
note, that merge table children are automatically added to
2018+
prelocking set in ha_myisammrg::add_children_list(), but their
2019+
TABLE_LIST's are on the execution arena, so tl will be invalid
2020+
on the second execution. Let's just skip them below.
2021+
*/
2022+
if (table_list->parent_l || !tl ||
2023+
table_list->for_insert_data != tl->for_insert_data)
2024+
distance|= 1;
20142025

20152026
/*
20162027
Find a table that either has the exact lock type requested,

0 commit comments

Comments
 (0)