Browse Source

MDEV-37172 Server crashes in Item_func_nextval::update_table after INSERT to the table, that uses expression with nextval() as default

The issue was that unpack_vcol_info_from_frm() wrongly linked the used
sequence tables into tables->internal_tables when more than one sequence
table was used.

Other things:
- Fixed internal_table_exists() to take db into account.
  (This is making the code easier to read. As we where comparing
   pointers the old code also worked).
bb-10.6-mdev-35713-hf
Monty 3 weeks ago
parent
commit
6058e02732
  1. 33
      mysql-test/suite/sql_sequence/default.result
  2. 23
      mysql-test/suite/sql_sequence/default.test
  3. 8
      sql/sql_base.cc
  4. 4
      sql/sql_parse.cc
  5. 10
      sql/table.cc

33
mysql-test/suite/sql_sequence/default.result

@ -313,4 +313,37 @@ insert v1 values (default);
ERROR HY000: The target table v1 of the INSERT is not insertable-into
drop view v1;
drop table t1;
#
# MDEV-37172 Server crashes in Item_func_nextval::update_table after
# INSERT to the table, that uses expression with nextval() as default
#
create sequence s1;
create sequence s2;
create table t1 (id int default(nextval(s1)));
create table t2 (id int default(nextval(s1)+nextval(s1)));
create table t3 (id1 int default(nextval(s1)+nextval(s1)),
id2 int default(nextval(s2)));
insert t1 values ();
select lastval(s1);
lastval(s1)
1
select * from t1;
id
1
insert t2 values ();
select lastval(s1);
lastval(s1)
3
select * from t2;
id
5
insert t3 values ();
select lastval(s1), lastval(s2);
lastval(s1) lastval(s2)
5 1
select * from t3;
id1 id2
9 1
drop table t1,t2,t3;
drop sequence s1,s2;
# End of 10.6 tests

23
mysql-test/suite/sql_sequence/default.test

@ -240,4 +240,27 @@ insert v1 values (default);
drop view v1;
drop table t1;
--echo #
--echo # MDEV-37172 Server crashes in Item_func_nextval::update_table after
--echo # INSERT to the table, that uses expression with nextval() as default
--echo #
create sequence s1;
create sequence s2;
create table t1 (id int default(nextval(s1)));
create table t2 (id int default(nextval(s1)+nextval(s1)));
create table t3 (id1 int default(nextval(s1)+nextval(s1)),
id2 int default(nextval(s2)));
insert t1 values ();
select lastval(s1);
select * from t1;
insert t2 values ();
select lastval(s1);
select * from t2;
insert t3 values ();
select lastval(s1), lastval(s2);
select * from t3;
drop table t1,t2,t3;
drop sequence s1,s2;
--echo # End of 10.6 tests

8
sql/sql_base.cc

@ -4722,11 +4722,12 @@ bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_CSTRING *db,
static TABLE_LIST *internal_table_exists(TABLE_LIST *global_list,
const char *table_name)
TABLE_LIST *table)
{
do
{
if (global_list->table_name.str == table_name)
if (global_list->table_name.str == table->table_name.str &&
global_list->db.str == table->db.str)
return global_list;
} while ((global_list= global_list->next_global));
return 0;
@ -4747,8 +4748,7 @@ add_internal_tables(THD *thd, Query_tables_list *prelocking_ctx,
/*
Skip table if already in the list. Can happen with prepared statements
*/
if ((tmp= internal_table_exists(global_table_list,
tables->table_name.str)))
if ((tmp= internal_table_exists(global_table_list, tables)))
{
/*
Use the original value for the next local, used by the

4
sql/sql_parse.cc

@ -8438,8 +8438,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
}
}
}
/* Store the table reference preceding the current one. */
TABLE_LIST *UNINIT_VAR(previous_table_ref); /* The table preceding the current one. */
/* Store the table reference preceding the current in previous_table_ref */
TABLE_LIST *UNINIT_VAR(previous_table_ref);
if (table_list.elements > 0 && likely(!ptr->sequence))
{
/*

10
sql/table.cc

@ -3942,6 +3942,7 @@ unpack_vcol_info_from_frm(THD *thd, TABLE *table,
LEX *old_lex= thd->lex;
LEX lex;
bool error;
TABLE_LIST *sequence, *last;
DBUG_ENTER("unpack_vcol_info_from_frm");
DBUG_ASSERT(vcol->expr == NULL);
@ -3959,11 +3960,12 @@ unpack_vcol_info_from_frm(THD *thd, TABLE *table,
if (unlikely(error))
goto end;
if (lex.current_select->table_list.first[0].next_global)
if ((sequence= lex.current_select->table_list.first[0].next_global))
{
/* We are using NEXT VALUE FOR sequence. Remember table name for open */
TABLE_LIST *sequence= lex.current_select->table_list.first[0].next_global;
sequence->next_global= table->internal_tables;
/* We are using NEXT VALUE FOR sequence. Remember table for open */
for (last= sequence ; last->next_global ; last= last->next_global)
;
last->next_global= table->internal_tables;
table->internal_tables= sequence;
}

Loading…
Cancel
Save