diff options
author | unknown <istruewing@chilla.local> | 2006-09-29 13:23:33 +0200 |
---|---|---|
committer | unknown <istruewing@chilla.local> | 2006-09-29 13:23:33 +0200 |
commit | 1373144ea5a7f27acff64158071ece0fd3dafc73 (patch) | |
tree | 7afd46f9e6203ab6650abc3d800127320df80efc | |
parent | de61d95bbcedc4fede0d4e56466828a3c71b8df4 (diff) | |
download | mariadb-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.result | 2 | ||||
-rw-r--r-- | sql/sql_insert.cc | 87 |
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 |