mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
Make SEQUENCE working with replication
- Old sequence code forced row based replication for any statements that refered to a sequence table. What is new is that row based replication is now sequence aware: - NEXT VALUE is now generating a short row based event with only next_value and round being replicated. - Short row based events are now on the slave updated as trough SET_VALUE(sequence_name) - Full row based events are on the slave updated with a full insert, which is practically same as ALTER SEQUENCE. - INSERT on a SEQUENCE table does now a EXCLUSIVE LOCK to ensure that it is logged in binary log before any following NEXT VALUE calls. - Enable all sequence tests and fixed found bugs - ALTER SEQUENCE doesn't anymore allow changes that makes the next_value outside of allowed range - SEQUENCE changes are done with TL_WRITE_ALLOW_WRITE. Because of this one can generate a statement for MyISAM with both TL_WRITE_CONCURRENT_INSERT and TL_WRITE_ALLOW_WRITE. To fix a warning I had to add an extra test in thr_lock.c for this. - Removed UPDATE of SEQUENCE (no need to support this as we have ALTER SEQUENCE, which takes the EXCLUSIVE lock properly. - Removed DBUG_ASSERT() in MDL_context::upgrade_shared_lock. This was removed upstream in MySQL 5.6 in 72f823de453. - Simplified test in decided_logging_format() by using sql_command_flags() - Fix that we log DROP SEQUENCE correctly. - Fixed that Aria works with SEQUENCE
This commit is contained in:
@ -20,6 +20,7 @@
|
||||
#include "sql_sequence.h"
|
||||
#include "ha_sequence.h"
|
||||
#include "sql_base.h"
|
||||
#include "sql_table.h" // write_bin_log
|
||||
#include "transaction.h"
|
||||
#include "lock.h"
|
||||
#include "sql_acl.h"
|
||||
@ -70,50 +71,60 @@ static Field_definition sequence_structure[]=
|
||||
Check whether sequence values are valid.
|
||||
Sets default values for fields that are not used, according to Oracle spec.
|
||||
|
||||
Note that reserved_until is not checked as it's ok that it's outside of
|
||||
the range (to indicate that sequence us used up).
|
||||
|
||||
RETURN VALUES
|
||||
false valid
|
||||
true invalid
|
||||
*/
|
||||
|
||||
bool sequence_definition::check_and_adjust()
|
||||
bool sequence_definition::check_and_adjust(bool set_reserved_until)
|
||||
{
|
||||
longlong max_increment;
|
||||
DBUG_ENTER("sequence_definition::check");
|
||||
|
||||
if (!(real_increment= increment))
|
||||
real_increment= global_system_variables.auto_increment_increment;
|
||||
|
||||
/*
|
||||
If min_value is not set, set it to LONGLONG_MIN or 1, depending on
|
||||
increment
|
||||
*/
|
||||
if (!(used_fields & seq_field_used_min_value))
|
||||
min_value= increment < 0 ? LONGLONG_MIN+1 : 1;
|
||||
min_value= real_increment < 0 ? LONGLONG_MIN+1 : 1;
|
||||
|
||||
/*
|
||||
If min_value is not set, set it to LONGLONG_MAX or -1, depending on
|
||||
increment
|
||||
real_increment
|
||||
*/
|
||||
if (!(used_fields & seq_field_used_max_value))
|
||||
max_value= increment < 0 ? -1 : LONGLONG_MAX-1;
|
||||
max_value= real_increment < 0 ? -1 : LONGLONG_MAX-1;
|
||||
|
||||
if (!(used_fields & seq_field_used_start))
|
||||
{
|
||||
/* Use min_value or max_value for start depending on increment */
|
||||
start= increment < 0 ? max_value : min_value;
|
||||
/* Use min_value or max_value for start depending on real_increment */
|
||||
start= real_increment < 0 ? max_value : min_value;
|
||||
}
|
||||
|
||||
/* To ensure that cache * increment will never overflow */
|
||||
max_increment= increment ? labs(increment) : MAX_AUTO_INCREMENT_VALUE;
|
||||
if (set_reserved_until)
|
||||
reserved_until= start;
|
||||
|
||||
adjust_values(reserved_until);
|
||||
|
||||
/* To ensure that cache * real_increment will never overflow */
|
||||
max_increment= (real_increment ?
|
||||
labs(real_increment) :
|
||||
MAX_AUTO_INCREMENT_VALUE);
|
||||
|
||||
if (max_value >= start &&
|
||||
max_value > min_value &&
|
||||
start >= min_value &&
|
||||
max_value != LONGLONG_MAX &&
|
||||
min_value != LONGLONG_MIN &&
|
||||
cache < (LONGLONG_MAX - max_increment) / max_increment)
|
||||
cache < (LONGLONG_MAX - max_increment) / max_increment &&
|
||||
((real_increment > 0 && reserved_until >= min_value) ||
|
||||
(real_increment < 0 && reserved_until <= max_value)))
|
||||
DBUG_RETURN(FALSE);
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
DBUG_RETURN(TRUE); // Error
|
||||
}
|
||||
|
||||
|
||||
@ -448,7 +459,7 @@ int SEQUENCE::read_stored_values()
|
||||
Adjust values after reading a the stored state
|
||||
*/
|
||||
|
||||
void SEQUENCE::adjust_values(longlong next_value)
|
||||
void sequence_definition::adjust_values(longlong next_value)
|
||||
{
|
||||
next_free_value= next_value;
|
||||
if (!(real_increment= increment))
|
||||
@ -531,17 +542,26 @@ int sequence_definition::write_initial_sequence(TABLE *table)
|
||||
Store current sequence values into the sequence table
|
||||
*/
|
||||
|
||||
int sequence_definition::write(TABLE *table)
|
||||
int sequence_definition::write(TABLE *table, bool all_fields)
|
||||
{
|
||||
int error;
|
||||
MY_BITMAP *save_rpl_write_set, *save_write_set;
|
||||
|
||||
/* Log a full insert (ok as table is small) */
|
||||
save_rpl_write_set= table->rpl_write_set;
|
||||
if (likely(!all_fields))
|
||||
{
|
||||
/* Only write next_value and round to binary log */
|
||||
table->rpl_write_set= &table->def_rpl_write_set;
|
||||
bitmap_clear_all(table->rpl_write_set);
|
||||
bitmap_set_bit(table->rpl_write_set, NEXT_FIELD_NO);
|
||||
bitmap_set_bit(table->rpl_write_set, ROUND_FIELD_NO);
|
||||
}
|
||||
else
|
||||
table->rpl_write_set= &table->s->all_set;
|
||||
|
||||
/* Update table */
|
||||
save_write_set= table->write_set;
|
||||
table->rpl_write_set= table->write_set= &table->s->all_set;
|
||||
table->write_set= &table->s->all_set;
|
||||
store_fields(table);
|
||||
/* Tell ha_sequence::write_row that we already hold the mutex */
|
||||
((ha_sequence*) table->file)->sequence_locked= 1;
|
||||
@ -612,7 +632,7 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error)
|
||||
The cache value is checked on insert so the following can't
|
||||
overflow
|
||||
*/
|
||||
add_to= cache ? real_increment * cache : 1;
|
||||
add_to= cache ? real_increment * cache : real_increment;
|
||||
out_of_values= 0;
|
||||
|
||||
if (real_increment > 0)
|
||||
@ -651,7 +671,7 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error)
|
||||
DBUG_RETURN(next_value(table, 1, error));
|
||||
}
|
||||
|
||||
if ((*error= write(table)))
|
||||
if ((*error= write(table, 0)))
|
||||
{
|
||||
reserved_until= org_reserved_until;
|
||||
next_free_value= res_value;
|
||||
@ -751,7 +771,7 @@ bool SEQUENCE::set_value(TABLE *table, longlong next_val, ulonglong next_round,
|
||||
needs_to_be_stored)
|
||||
{
|
||||
reserved_until= next_free_value;
|
||||
if (write(table))
|
||||
if (write(table, 0))
|
||||
{
|
||||
reserved_until= org_reserved_until;
|
||||
next_free_value= org_next_free_value;
|
||||
@ -842,7 +862,7 @@ bool Sql_cmd_alter_sequence::execute(THD *thd)
|
||||
|
||||
/* Let check_and_adjust think all fields are used */
|
||||
new_seq->used_fields= ~0;
|
||||
if (new_seq->check_and_adjust())
|
||||
if (new_seq->check_and_adjust(0))
|
||||
{
|
||||
my_error(ER_SEQUENCE_INVALID_DATA, MYF(0),
|
||||
first_table->db,
|
||||
@ -851,17 +871,22 @@ bool Sql_cmd_alter_sequence::execute(THD *thd)
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(error= new_seq->write(table)))
|
||||
if (!(error= new_seq->write(table, 1)))
|
||||
{
|
||||
/* Store the sequence values in table share */
|
||||
table->s->sequence->copy(new_seq);
|
||||
}
|
||||
trans_commit_stmt(thd);
|
||||
trans_commit_implicit(thd);
|
||||
else
|
||||
table->file->print_error(error, MYF(0));
|
||||
if (trans_commit_stmt(thd))
|
||||
error= 1;
|
||||
if (trans_commit_implicit(thd))
|
||||
error= 1;
|
||||
if (!error)
|
||||
error= write_bin_log(thd, 1, thd->query(), thd->query_length());
|
||||
if (!error)
|
||||
my_ok(thd);
|
||||
|
||||
end:
|
||||
close_thread_tables(thd);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
Reference in New Issue
Block a user