summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <istruewing@chilla.local>2006-09-29 13:23:33 +0200
committerunknown <istruewing@chilla.local>2006-09-29 13:23:33 +0200
commit1373144ea5a7f27acff64158071ece0fd3dafc73 (patch)
tree7afd46f9e6203ab6650abc3d800127320df80efc
parentde61d95bbcedc4fede0d4e56466828a3c71b8df4 (diff)
downloadmariadb-git-1373144ea5a7f27acff64158071ece0fd3dafc73.tar.gz
Bug#20830 - INSERT DELAYED does not honour SET INSERT_ID
Bug#20627 - INSERT DELAYED does not honour auto_increment_* variables Merge from 5.0. Changed auto_increment handling to the 5.1 pattern. mysql-test/r/delayed.result: Bug#20830 - INSERT DELAYED does not honour SET INSERT_ID Bug#20627 - INSERT DELAYED does not honour auto_increment_* variables Merge from 5.0. Updated the test result.
-rw-r--r--mysql-test/r/delayed.result2
-rw-r--r--sql/sql_insert.cc87
2 files changed, 50 insertions, 39 deletions
diff --git a/mysql-test/r/delayed.result b/mysql-test/r/delayed.result
index 6295fceec2b..a514ffcddd2 100644
--- a/mysql-test/r/delayed.result
+++ b/mysql-test/r/delayed.result
@@ -144,7 +144,7 @@ INSERT INTO t1 VALUES( 49, 71), (NULL, 72), (NULL, 73);
INSERT INTO t1 VALUES(NULL, 81), (NULL, 82), (NULL, 83);
SET insert_id= 114;
INSERT INTO t1 VALUES(NULL, 91);
-ERROR 23000: Duplicate entry '114' for key 1
+ERROR 23000: Duplicate entry '114' for key 'PRIMARY'
INSERT INTO t1 VALUES (NULL, 92), (NULL, 93);
SELECT * FROM t1;
c1 c2
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 714affa0616..b4966be48a2 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -572,7 +572,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
free_underlaid_joins(thd, &thd->lex->select_lex);
joins_freed= TRUE;
- table->file->ha_release_auto_increment();
/*
Now all rows are inserted. Time to update logs and sends response to
@@ -591,6 +590,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
else
#endif
{
+ /*
+ Do not do this release if this is a delayed insert, it would steal
+ auto_inc values from the delayed_insert thread as they share TABLE.
+ */
+ table->file->ha_release_auto_increment();
if (!thd->prelocked_mode && table->file->ha_end_bulk_insert() && !error)
{
table->file->print_error(my_errno,MYF(0));
@@ -1330,7 +1334,7 @@ public:
bool query_start_used, ignore, log_query;
bool stmt_depends_on_first_successful_insert_id_in_prev_stmt;
ulonglong first_successful_insert_id_in_prev_stmt;
- ulonglong next_insert_id;
+ ulonglong forced_insert_id;
ulong auto_increment_increment;
ulong auto_increment_offset;
timestamp_auto_set_type timestamp_field_type;
@@ -1339,7 +1343,7 @@ public:
delayed_row(LEX_STRING const query_arg, enum_duplicates dup_arg,
bool ignore_arg, bool log_query_arg)
: record(0), dup(dup_arg), ignore(ignore_arg), log_query(log_query_arg),
- query(query_arg)
+ forced_insert_id(0), query(query_arg)
{}
~delayed_row()
{
@@ -1697,6 +1701,7 @@ write_delayed(THD *thd,TABLE *table, enum_duplicates duplic,
{
delayed_row *row;
delayed_insert *di=thd->di;
+ const Discrete_interval *forced_auto_inc;
DBUG_ENTER("write_delayed");
DBUG_PRINT("enter", ("query = '%s' length %u", query.str, query.length));
@@ -1746,21 +1751,16 @@ write_delayed(THD *thd,TABLE *table, enum_duplicates duplic,
thd->first_successful_insert_id_in_prev_stmt;
row->timestamp_field_type= table->timestamp_field_type;
- /* The session variable settings can always be copied. */
+ /* Copy session variables. */
row->auto_increment_increment= thd->variables.auto_increment_increment;
row->auto_increment_offset= thd->variables.auto_increment_offset;
- /*
- Next insert id must be set for the first value in a multi-row insert
- only. So clear it after the first use. Assume a multi-row insert.
- Since the user thread doesn't really execute the insert,
- thd->next_insert_id is left untouched between the rows. If we copy
- the same insert id to every row of the multi-row insert, the delayed
- insert thread would copy this before inserting every row. Thus it
- tries to insert all rows with the same insert id. This fails on the
- unique constraint. So just the first row would be really inserted.
- */
- row->next_insert_id= thd->next_insert_id;
- thd->next_insert_id= 0;
+ /* Copy the next forced auto increment value, if any. */
+ if ((forced_auto_inc= thd->auto_inc_intervals_forced.get_next()))
+ {
+ row->forced_insert_id= forced_auto_inc->minimum();
+ DBUG_PRINT("delayed", ("transmitting auto_inc: %lu",
+ (ulong) row->forced_insert_id));
+ }
di->rows.push_back(row);
di->stacked_inserts++;
@@ -2013,6 +2013,10 @@ pthread_handler_t handle_delayed_insert(void *arg)
MYSQL_LOCK *lock=thd->lock;
thd->lock=0;
pthread_mutex_unlock(&di->mutex);
+ /*
+ We need to release next_insert_id before unlocking. This is
+ enforced by handler::ha_external_lock().
+ */
di->table->file->ha_release_auto_increment();
mysql_unlock_tables(thd, lock);
di->group_count=0;
@@ -2133,21 +2137,42 @@ bool delayed_insert::handle_inserts(void)
thd.start_time=row->start_time;
thd.query_start_used=row->query_start_used;
- /* for the binlog, forget auto_increment ids generated by previous rows */
-// thd.auto_inc_intervals_in_cur_stmt_for_binlog.empty();
+ /*
+ To get the exact auto_inc interval to store in the binlog we must not
+ use values from the previous interval (of the previous rows).
+ */
+ bool log_query= (row->log_query && row->query.str != NULL);
+ DBUG_PRINT("delayed", ("query: '%s' length: %u", row->query.str ?
+ row->query.str : "[NULL]", row->query.length));
+ if (row->query.str)
+ {
+ /*
+ This is the first value of an INSERT statement.
+ It is the right place to clear a forced insert_id.
+ This is usually done after the last value of an INSERT statement,
+ but we won't know this in the insert delayed thread. But before
+ the first value is sufficiently equivalent to after the last
+ value of the previous statement.
+ */
+ table->file->ha_release_auto_increment();
+ thd.auto_inc_intervals_in_cur_stmt_for_binlog.empty();
+ }
thd.first_successful_insert_id_in_prev_stmt=
row->first_successful_insert_id_in_prev_stmt;
thd.stmt_depends_on_first_successful_insert_id_in_prev_stmt=
row->stmt_depends_on_first_successful_insert_id_in_prev_stmt;
table->timestamp_field_type= row->timestamp_field_type;
- /* The session variable settings can always be copied. */
+ /* Copy the session variables. */
thd.variables.auto_increment_increment= row->auto_increment_increment;
thd.variables.auto_increment_offset= row->auto_increment_offset;
- /* Next insert id must be used only if non-zero. */
- if (row->next_insert_id)
- thd.next_insert_id= row->next_insert_id;
- DBUG_PRINT("loop", ("next_insert_id: %lu", (ulong) thd.next_insert_id));
+ /* Copy a forced insert_id, if any. */
+ if (row->forced_insert_id)
+ {
+ DBUG_PRINT("delayed", ("received auto_inc: %lu",
+ (ulong) row->forced_insert_id));
+ thd.force_one_auto_inc_interval(row->forced_insert_id);
+ }
info.ignore= row->ignore;
info.handle_duplicates= row->dup;
@@ -2170,20 +2195,6 @@ bool delayed_insert::handle_inserts(void)
info.error_count++; // Ignore errors
thread_safe_increment(delayed_insert_errors,&LOCK_delayed_status);
row->log_query = 0;
- /*
- We must reset next_insert_id. Otherwise all following rows may
- become duplicates. If write_record() failed on a duplicate and
- next_insert_id would be left unchanged, the next rows would also
- be tried with the same insert id and would fail. Since the end
- of a multi-row statement is unknown here, all following rows in
- the queue would be dropped, regardless which thread added them.
- After the queue is used up, next_insert_id is cleared and the
- next run will succeed. This could even happen if these come from
- the same multi-row statement as the current queue contents. That
- way it would look somewhat random which rows are rejected after
- a duplicate.
- */
- thd.next_insert_id= 0;
}
if (using_ignore)
@@ -2197,7 +2208,7 @@ bool delayed_insert::handle_inserts(void)
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
}
- if (row->log_query && row->query.str != NULL && mysql_bin_log.is_open())
+ if (log_query && mysql_bin_log.is_open())
{
/*
If the query has several rows to insert, only the first row will come