1
0
mirror of https://github.com/MariaDB/server.git synced 2026-01-06 05:22:24 +03:00

Fix for BUG#31612

"Trigger fired multiple times leads to gaps in auto_increment sequence".
The bug was that if a trigger fired multiple times inside a top
statement (for example top-statement is a multi-row INSERT,
and trigger is ON INSERT), and that trigger inserted into an auto_increment
column, then gaps could be observed in the auto_increment sequence,
even if there were no other users of the database (no concurrency).
It was wrong usage of THD::auto_inc_intervals_in_cur_stmt_for_binlog.
Note that the fix changes "class handler", I'll tell the Storage Engine API team.
This commit is contained in:
Guilhem Bichot
2008-10-06 16:06:59 +02:00
parent 0b097b7777
commit f8670e2c53
6 changed files with 68 additions and 17 deletions

View File

@@ -2165,7 +2165,12 @@ prev_insert_id(ulonglong nr, struct system_variables *variables)
- In both cases, the reserved intervals are remembered in
thd->auto_inc_intervals_in_cur_stmt_for_binlog if statement-based
binlogging; the last reserved interval is remembered in
auto_inc_interval_for_cur_row.
auto_inc_interval_for_cur_row. The number of reserved intervals is
remembered in auto_inc_intervals_count. It differs from the number of
elements in thd->auto_inc_intervals_in_cur_stmt_for_binlog() because the
latter list is cumulative over all statements forming one binlog event
(when stored functions and triggers are used), and collapses two
contiguous intervals in one (see its append() method).
The idea is that generated auto_increment values are predictable and
independent of the column values in the table. This is needed to be
@@ -2249,8 +2254,6 @@ int handler::update_auto_increment()
handler::estimation_rows_to_insert was set by
handler::ha_start_bulk_insert(); if 0 it means "unknown".
*/
uint nb_already_reserved_intervals=
thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements();
ulonglong nb_desired_values;
/*
If an estimation was given to the engine:
@@ -2262,17 +2265,17 @@ int handler::update_auto_increment()
start, starting from AUTO_INC_DEFAULT_NB_ROWS.
Don't go beyond a max to not reserve "way too much" (because
reservation means potentially losing unused values).
Note that in prelocked mode no estimation is given.
*/
if (nb_already_reserved_intervals == 0 &&
(estimation_rows_to_insert > 0))
if ((auto_inc_intervals_count == 0) && (estimation_rows_to_insert > 0))
nb_desired_values= estimation_rows_to_insert;
else /* go with the increasing defaults */
{
/* avoid overflow in formula, with this if() */
if (nb_already_reserved_intervals <= AUTO_INC_DEFAULT_NB_MAX_BITS)
if (auto_inc_intervals_count <= AUTO_INC_DEFAULT_NB_MAX_BITS)
{
nb_desired_values= AUTO_INC_DEFAULT_NB_ROWS *
(1 << nb_already_reserved_intervals);
nb_desired_values= AUTO_INC_DEFAULT_NB_ROWS *
(1 << auto_inc_intervals_count);
set_if_smaller(nb_desired_values, AUTO_INC_DEFAULT_NB_MAX);
}
else
@@ -2285,7 +2288,7 @@ int handler::update_auto_increment()
&nb_reserved_values);
if (nr == ~(ulonglong) 0)
DBUG_RETURN(HA_ERR_AUTOINC_READ_FAILED); // Mark failure
/*
That rounding below should not be needed when all engines actually
respect offset and increment in get_auto_increment(). But they don't
@@ -2296,7 +2299,7 @@ int handler::update_auto_increment()
*/
nr= compute_next_insert_id(nr-1, variables);
}
if (table->s->next_number_keypart == 0)
{
/* We must defer the appending until "nr" has been possibly truncated */
@@ -2340,8 +2343,9 @@ int handler::update_auto_increment()
{
auto_inc_interval_for_cur_row.replace(nr, nb_reserved_values,
variables->auto_increment_increment);
auto_inc_intervals_count++;
/* Row-based replication does not need to store intervals in binlog */
if (!thd->current_stmt_binlog_row_based)
if (mysql_bin_log.is_open() && !thd->current_stmt_binlog_row_based)
thd->auto_inc_intervals_in_cur_stmt_for_binlog.append(auto_inc_interval_for_cur_row.minimum(),
auto_inc_interval_for_cur_row.values(),
variables->auto_increment_increment);
@@ -2461,6 +2465,7 @@ void handler::ha_release_auto_increment()
release_auto_increment();
insert_id_for_cur_row= 0;
auto_inc_interval_for_cur_row.replace(0, 0, 0);
auto_inc_intervals_count= 0;
if (next_insert_id > 0)
{
next_insert_id= 0;