Skip to content

Commit

Permalink
Fixed crash with SEQUENCE when using REPAIR
Browse files Browse the repository at this point in the history
  • Loading branch information
montywi committed May 7, 2017
1 parent c619fbe commit 276b0c8
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 7 deletions.
42 changes: 42 additions & 0 deletions mysql-test/suite/sql_sequence/other.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#
# Create and check
#
create sequence s1 engine=innodb;
check table s1;
Table Op Msg_type Msg_text
test.s1 check note The storage engine for the table doesn't support check
select next value for s1;
next value for s1
1
flush tables;
check table s1;
Table Op Msg_type Msg_text
test.s1 check note The storage engine for the table doesn't support check
select next value for s1;
next value for s1
1001
flush tables;
repair table s1;
Table Op Msg_type Msg_text
test.s1 repair note The storage engine for the table doesn't support repair
select next value for s1;
next value for s1
2001
drop sequence s1;
create or replace sequence s1 engine=innodb;
select next value for s1;
next value for s1
1
repair table s1;
Table Op Msg_type Msg_text
test.s1 repair note The storage engine for the table doesn't support repair
check table s1;
Table Op Msg_type Msg_text
test.s1 check note The storage engine for the table doesn't support check
select next value for s1;
next value for s1
1001
select * from s1;
next_value min_value max_value start increment cache cycle round
2001 1 9223372036854775806 1 1 1000 0 0
drop sequence s1;
29 changes: 29 additions & 0 deletions mysql-test/suite/sql_sequence/other.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
--source include/have_sequence.inc
--source include/have_innodb.inc

#
# Test various combinations of operations on sequence
#

--echo #
--echo # Create and check
--echo #

create sequence s1 engine=innodb;
check table s1;
select next value for s1;
flush tables;
check table s1;
select next value for s1;
flush tables;
repair table s1;
select next value for s1;
drop sequence s1;

create or replace sequence s1 engine=innodb;
select next value for s1;
repair table s1;
check table s1;
select next value for s1;
select * from s1;
drop sequence s1;
6 changes: 5 additions & 1 deletion sql/ha_sequence.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ int ha_sequence::open(const char *name, int mode, uint flags)
if ((error= table->s->sequence->read_initial_values(table)))
file->ha_close();
}
else
table->m_needs_reopen= true;
}
DBUG_RETURN(error);
}
Expand Down Expand Up @@ -189,11 +191,13 @@ int ha_sequence::write_row(uchar *buf)
DBUG_ASSERT(table->record[0] == buf);

row_already_logged= 0;
if (!sequence->initialized)
if (unlikely(sequence->initialized == SEQUENCE::SEQ_IN_PREPARE))
{
/* This calls is from ha_open() as part of create table */
DBUG_RETURN(file->write_row(buf));
}
if (unlikely(sequence->initialized != SEQUENCE::SEQ_READY_TO_USE))
DBUG_RETURN(HA_ERR_WRONG_COMMAND);

/*
User tries to write a row
Expand Down
12 changes: 7 additions & 5 deletions sql/sql_sequence.cc
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,9 @@ bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *table_list)
tmp_disable_binlog(thd);
save_write_set= table->write_set;
table->write_set= &table->s->all_set;
table->s->sequence->initialized= SEQUENCE::SEQ_IN_PREPARE;
error= table->file->ha_write_row(table->record[0]);
table->s->sequence->initialized= SEQUENCE::SEQ_UNINTIALIZED;
reenable_binlog(thd);
table->write_set= save_write_set;

Expand All @@ -339,7 +341,7 @@ bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *table_list)
Sequence structure is up to date and table has one row,
sequence is now usable
*/
table->s->sequence->initialized= 1;
table->s->sequence->initialized= SEQUENCE::SEQ_READY_TO_USE;
}

trans_commit_stmt(thd);
Expand All @@ -353,7 +355,7 @@ bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *table_list)

/* Create a SQUENCE object */

SEQUENCE::SEQUENCE() :initialized(0), all_values_used(0), table(0)
SEQUENCE::SEQUENCE() :all_values_used(0), initialized(SEQ_UNINTIALIZED), table(0)
{
mysql_mutex_init(key_LOCK_SEQUENCE, &mutex, MY_MUTEX_INIT_SLOW);
}
Expand All @@ -376,11 +378,11 @@ int SEQUENCE::read_initial_values(TABLE *table_arg)
MDL_request mdl_request; // Empty constructor!
DBUG_ENTER("SEQUENCE::read_initial_values");

if (likely(initialized))
if (likely(initialized != SEQ_UNINTIALIZED))
DBUG_RETURN(0);
table= table_arg;
mysql_mutex_lock(&mutex);
if (unlikely(!initialized))
if (likely(initialized == SEQ_UNINTIALIZED))
{
MYSQL_LOCK *lock;
bool mdl_lock_used= 0;
Expand Down Expand Up @@ -419,7 +421,7 @@ int SEQUENCE::read_initial_values(TABLE *table_arg)
DBUG_RETURN(HA_ERR_LOCK_WAIT_TIMEOUT);
}
if (!(error= read_stored_values()))
initialized= 1;
initialized= SEQ_READY_TO_USE;
mysql_unlock_tables(thd, lock, 0);
if (mdl_lock_used)
thd->mdl_context.release_lock(mdl_request.ticket);
Expand Down
4 changes: 3 additions & 1 deletion sql/sql_sequence.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class sequence_definition :public Sql_alloc
class SEQUENCE :public sequence_definition
{
public:
enum seq_init { SEQ_UNINTIALIZED, SEQ_IN_PREPARE, SEQ_READY_TO_USE };
SEQUENCE();
~SEQUENCE();
int read_initial_values(TABLE *table);
Expand All @@ -87,8 +88,9 @@ class SEQUENCE :public sequence_definition
}
longlong next_value(TABLE *table, bool second_round, int *error);

bool initialized; // If row has been read
bool all_values_used;
seq_init initialized;

private:
TABLE *table;
mysql_mutex_t mutex;
Expand Down

0 comments on commit 276b0c8

Please sign in to comment.