diff --git a/mysql-test/r/delayed.result b/mysql-test/r/delayed.result index a336f3b4108..a514ffcddd2 100644 --- a/mysql-test/r/delayed.result +++ b/mysql-test/r/delayed.result @@ -7,6 +7,7 @@ insert delayed into t1 set a = 4; insert delayed into t1 set a = 5, tmsp = 19711006010203; insert delayed into t1 (a, tmsp) values (6, 19711006010203); insert delayed into t1 (a, tmsp) values (7, NULL); +FLUSH TABLE t1; insert into t1 set a = 8,tmsp=19711006010203; select * from t1 where tmsp=0; a tmsp @@ -22,6 +23,7 @@ insert delayed into t1 values (null,"c"); insert delayed into t1 values (3,"d"),(null,"e"); insert delayed into t1 values (3,"this will give an","error"); ERROR 21S01: Column count doesn't match value count at row 1 +FLUSH TABLE t1; show status like 'not_flushed_delayed_rows'; Variable_name Value Not_flushed_delayed_rows 0 @@ -54,6 +56,7 @@ insert delayed into t1 values(null); insert delayed into t1 values(null); insert delayed into t1 values(null); insert delayed into t1 values(null); +FLUSH TABLE t1; select * from t1 order by a; a 1 @@ -69,3 +72,174 @@ a 12 13 DROP TABLE t1; +SET @bug20627_old_auto_increment_offset= +@@auto_increment_offset= 2; +SET @bug20627_old_auto_increment_increment= +@@auto_increment_increment= 3; +SET @bug20627_old_session_auto_increment_offset= +@@session.auto_increment_offset= 4; +SET @bug20627_old_session_auto_increment_increment= +@@session.auto_increment_increment= 5; +SET @@auto_increment_offset= 2; +SET @@auto_increment_increment= 3; +SET @@session.auto_increment_offset= 4; +SET @@session.auto_increment_increment= 5; +CREATE TABLE t1 ( +c1 INT NOT NULL AUTO_INCREMENT, +PRIMARY KEY (c1) +); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL); +SELECT * FROM t1; +c1 +4 +9 +14 +DROP TABLE t1; +CREATE TABLE t1 ( +c1 INT NOT NULL AUTO_INCREMENT, +PRIMARY KEY (c1) +); +INSERT DELAYED INTO t1 VALUES (NULL),(NULL),(NULL); +FLUSH TABLE t1; +SELECT * FROM t1; +c1 +4 +9 +14 +DROP TABLE t1; +SET @@auto_increment_offset= +@bug20627_old_auto_increment_offset; +SET @@auto_increment_increment= +@bug20627_old_auto_increment_increment; +SET @@session.auto_increment_offset= +@bug20627_old_session_auto_increment_offset; +SET @@session.auto_increment_increment= +@bug20627_old_session_auto_increment_increment; +SET @bug20830_old_auto_increment_offset= +@@auto_increment_offset= 2; +SET @bug20830_old_auto_increment_increment= +@@auto_increment_increment= 3; +SET @bug20830_old_session_auto_increment_offset= +@@session.auto_increment_offset= 4; +SET @bug20830_old_session_auto_increment_increment= +@@session.auto_increment_increment= 5; +SET @@auto_increment_offset= 2; +SET @@auto_increment_increment= 3; +SET @@session.auto_increment_offset= 4; +SET @@session.auto_increment_increment= 5; +CREATE TABLE t1 ( +c1 INT(11) NOT NULL AUTO_INCREMENT, +c2 INT(11) DEFAULT NULL, +PRIMARY KEY (c1) +); +SET insert_id= 14; +INSERT INTO t1 VALUES(NULL, 11), (NULL, 12), (NULL, 13); +INSERT INTO t1 VALUES(NULL, 21), (NULL, 22), (NULL, 23); +INSERT INTO t1 VALUES( 69, 31), (NULL, 32), (NULL, 33); +INSERT INTO t1 VALUES(NULL, 41), (NULL, 42), (NULL, 43); +SET insert_id= 114; +INSERT INTO t1 VALUES(NULL, 51), (NULL, 52), (NULL, 53); +INSERT INTO t1 VALUES(NULL, 61), (NULL, 62), (NULL, 63); +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 'PRIMARY' +INSERT INTO t1 VALUES (NULL, 92), (NULL, 93); +SELECT * FROM t1; +c1 c2 +14 11 +19 12 +24 13 +29 21 +34 22 +39 23 +69 31 +74 32 +79 33 +84 41 +89 42 +94 43 +114 51 +119 52 +124 53 +129 61 +134 62 +139 63 +49 71 +144 72 +149 73 +154 81 +159 82 +164 83 +169 92 +174 93 +SELECT COUNT(*) FROM t1; +COUNT(*) +26 +SELECT SUM(c1) FROM t1; +SUM(c1) +2569 +DROP TABLE t1; +CREATE TABLE t1 ( +c1 INT(11) NOT NULL AUTO_INCREMENT, +c2 INT(11) DEFAULT NULL, +PRIMARY KEY (c1) +); +SET insert_id= 14; +INSERT DELAYED INTO t1 VALUES(NULL, 11), (NULL, 12), (NULL, 13); +INSERT DELAYED INTO t1 VALUES(NULL, 21), (NULL, 22), (NULL, 23); +INSERT DELAYED INTO t1 VALUES( 69, 31), (NULL, 32), (NULL, 33); +INSERT DELAYED INTO t1 VALUES(NULL, 41), (NULL, 42), (NULL, 43); +SET insert_id= 114; +INSERT DELAYED INTO t1 VALUES(NULL, 51), (NULL, 52), (NULL, 53); +INSERT DELAYED INTO t1 VALUES(NULL, 61), (NULL, 62), (NULL, 63); +INSERT DELAYED INTO t1 VALUES( 49, 71), (NULL, 72), (NULL, 73); +INSERT DELAYED INTO t1 VALUES(NULL, 81), (NULL, 82), (NULL, 83); +SET insert_id= 114; +INSERT DELAYED INTO t1 VALUES(NULL, 91); +INSERT DELAYED INTO t1 VALUES (NULL, 92), (NULL, 93); +FLUSH TABLE t1; +SELECT * FROM t1; +c1 c2 +14 11 +19 12 +24 13 +29 21 +34 22 +39 23 +69 31 +74 32 +79 33 +84 41 +89 42 +94 43 +114 51 +119 52 +124 53 +129 61 +134 62 +139 63 +49 71 +144 72 +149 73 +154 81 +159 82 +164 83 +169 92 +174 93 +SELECT COUNT(*) FROM t1; +COUNT(*) +26 +SELECT SUM(c1) FROM t1; +SUM(c1) +2569 +DROP TABLE t1; +SET @@auto_increment_offset= +@bug20830_old_auto_increment_offset; +SET @@auto_increment_increment= +@bug20830_old_auto_increment_increment; +SET @@session.auto_increment_offset= +@bug20830_old_session_auto_increment_offset; +SET @@session.auto_increment_increment= +@bug20830_old_session_auto_increment_increment; diff --git a/mysql-test/t/delayed.test b/mysql-test/t/delayed.test index 55e8f81f763..03d8e20dd8f 100644 --- a/mysql-test/t/delayed.test +++ b/mysql-test/t/delayed.test @@ -17,7 +17,8 @@ insert delayed into t1 set a = 4; insert delayed into t1 set a = 5, tmsp = 19711006010203; insert delayed into t1 (a, tmsp) values (6, 19711006010203); insert delayed into t1 (a, tmsp) values (7, NULL); ---sleep 2 +# Wait until the rows are flushed to the table files. +FLUSH TABLE t1; insert into t1 set a = 8,tmsp=19711006010203; select * from t1 where tmsp=0; select * from t1 where tmsp=19711006010203; @@ -34,8 +35,8 @@ insert delayed into t1 values (null,"c"); insert delayed into t1 values (3,"d"),(null,"e"); --error 1136 insert delayed into t1 values (3,"this will give an","error"); -# 2 was not enough for --ps-protocol ---sleep 4 +# Wait until the rows are flushed to the table files. +FLUSH TABLE t1; show status like 'not_flushed_delayed_rows'; select * from t1; drop table t1; @@ -92,10 +93,145 @@ insert delayed into t1 values(null); # Works, since the delayed-counter is 8, which is unused insert delayed into t1 values(null); +# Wait until the rows are flushed to the table files. +FLUSH TABLE t1; # Check what we have now -# must wait so that the delayed thread finishes -# Note: this must be increased if the test fails ---sleep 1 select * from t1 order by a; DROP TABLE t1; + +# +# Bug#20627 - INSERT DELAYED does not honour auto_increment_* variables +# +SET @bug20627_old_auto_increment_offset= + @@auto_increment_offset= 2; +SET @bug20627_old_auto_increment_increment= + @@auto_increment_increment= 3; +SET @bug20627_old_session_auto_increment_offset= + @@session.auto_increment_offset= 4; +SET @bug20627_old_session_auto_increment_increment= + @@session.auto_increment_increment= 5; +SET @@auto_increment_offset= 2; +SET @@auto_increment_increment= 3; +SET @@session.auto_increment_offset= 4; +SET @@session.auto_increment_increment= 5; +# +# Normal insert as reference. +CREATE TABLE t1 ( + c1 INT NOT NULL AUTO_INCREMENT, + PRIMARY KEY (c1) + ); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL); +# Check what we have now +SELECT * FROM t1; +DROP TABLE t1; +# +# Delayed insert. +CREATE TABLE t1 ( + c1 INT NOT NULL AUTO_INCREMENT, + PRIMARY KEY (c1) + ); +INSERT DELAYED INTO t1 VALUES (NULL),(NULL),(NULL); +# Wait until the rows are flushed to the table files. +FLUSH TABLE t1; +# Check what we have now +SELECT * FROM t1; +DROP TABLE t1; +# +# Cleanup +SET @@auto_increment_offset= + @bug20627_old_auto_increment_offset; +SET @@auto_increment_increment= + @bug20627_old_auto_increment_increment; +SET @@session.auto_increment_offset= + @bug20627_old_session_auto_increment_offset; +SET @@session.auto_increment_increment= + @bug20627_old_session_auto_increment_increment; + +# +# Bug#20830 - INSERT DELAYED does not honour SET INSERT_ID +# +SET @bug20830_old_auto_increment_offset= + @@auto_increment_offset= 2; +SET @bug20830_old_auto_increment_increment= + @@auto_increment_increment= 3; +SET @bug20830_old_session_auto_increment_offset= + @@session.auto_increment_offset= 4; +SET @bug20830_old_session_auto_increment_increment= + @@session.auto_increment_increment= 5; +SET @@auto_increment_offset= 2; +SET @@auto_increment_increment= 3; +SET @@session.auto_increment_offset= 4; +SET @@session.auto_increment_increment= 5; +# +# Normal insert as reference. +CREATE TABLE t1 ( + c1 INT(11) NOT NULL AUTO_INCREMENT, + c2 INT(11) DEFAULT NULL, + PRIMARY KEY (c1) + ); +SET insert_id= 14; +INSERT INTO t1 VALUES(NULL, 11), (NULL, 12), (NULL, 13); +INSERT INTO t1 VALUES(NULL, 21), (NULL, 22), (NULL, 23); +# Restart sequence at a different value. +INSERT INTO t1 VALUES( 69, 31), (NULL, 32), (NULL, 33); +INSERT INTO t1 VALUES(NULL, 41), (NULL, 42), (NULL, 43); +# Restart sequence at a different value. +SET insert_id= 114; +INSERT INTO t1 VALUES(NULL, 51), (NULL, 52), (NULL, 53); +INSERT INTO t1 VALUES(NULL, 61), (NULL, 62), (NULL, 63); +# Set one value below the maximum value. +INSERT INTO t1 VALUES( 49, 71), (NULL, 72), (NULL, 73); +INSERT INTO t1 VALUES(NULL, 81), (NULL, 82), (NULL, 83); +# Create a duplicate value. +SET insert_id= 114; +--error 1062 +INSERT INTO t1 VALUES(NULL, 91); +INSERT INTO t1 VALUES (NULL, 92), (NULL, 93); +# Check what we have now +SELECT * FROM t1; +SELECT COUNT(*) FROM t1; +SELECT SUM(c1) FROM t1; +DROP TABLE t1; +# +# Delayed insert. +CREATE TABLE t1 ( + c1 INT(11) NOT NULL AUTO_INCREMENT, + c2 INT(11) DEFAULT NULL, + PRIMARY KEY (c1) + ); +SET insert_id= 14; +INSERT DELAYED INTO t1 VALUES(NULL, 11), (NULL, 12), (NULL, 13); +INSERT DELAYED INTO t1 VALUES(NULL, 21), (NULL, 22), (NULL, 23); +# Restart sequence at a different value. +INSERT DELAYED INTO t1 VALUES( 69, 31), (NULL, 32), (NULL, 33); +INSERT DELAYED INTO t1 VALUES(NULL, 41), (NULL, 42), (NULL, 43); +# Restart sequence at a different value. +SET insert_id= 114; +INSERT DELAYED INTO t1 VALUES(NULL, 51), (NULL, 52), (NULL, 53); +INSERT DELAYED INTO t1 VALUES(NULL, 61), (NULL, 62), (NULL, 63); +# Set one value below the maximum value. +INSERT DELAYED INTO t1 VALUES( 49, 71), (NULL, 72), (NULL, 73); +INSERT DELAYED INTO t1 VALUES(NULL, 81), (NULL, 82), (NULL, 83); +# Create a duplicate value. +SET insert_id= 114; +INSERT DELAYED INTO t1 VALUES(NULL, 91); +INSERT DELAYED INTO t1 VALUES (NULL, 92), (NULL, 93); +# Wait until the rows are flushed to the table files. +FLUSH TABLE t1; +# Check what we have now +SELECT * FROM t1; +SELECT COUNT(*) FROM t1; +SELECT SUM(c1) FROM t1; +DROP TABLE t1; +# +# Cleanup +SET @@auto_increment_offset= + @bug20830_old_auto_increment_offset; +SET @@auto_increment_increment= + @bug20830_old_auto_increment_increment; +SET @@session.auto_increment_offset= + @bug20830_old_session_auto_increment_offset; +SET @@session.auto_increment_increment= + @bug20830_old_session_auto_increment_increment; + diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 1e7349456e4..23e4c413092 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,13 +1334,16 @@ 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 forced_insert_id; + ulong auto_increment_increment; + ulong auto_increment_offset; timestamp_auto_set_type timestamp_field_type; LEX_STRING query; 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() { @@ -1694,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)); @@ -1743,6 +1751,17 @@ 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; + /* Copy session variables. */ + row->auto_increment_increment= thd->variables.auto_increment_increment; + row->auto_increment_offset= thd->variables.auto_increment_offset; + /* 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++; di->status=1; @@ -1994,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; @@ -2114,14 +2137,43 @@ 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; + /* Copy the session variables. */ + thd.variables.auto_increment_increment= row->auto_increment_increment; + thd.variables.auto_increment_offset= row->auto_increment_offset; + /* 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; if (info.ignore || @@ -2156,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 @@ -2199,6 +2251,7 @@ bool delayed_insert::handle_inserts(void) /* This should never happen */ table->file->print_error(error,MYF(0)); sql_print_error("%s",thd.net.last_error); + DBUG_PRINT("error", ("HA_EXTRA_NO_CACHE failed in loop")); goto err; } query_cache_invalidate3(&thd, table, 1); @@ -2241,6 +2294,7 @@ bool delayed_insert::handle_inserts(void) { // This shouldn't happen table->file->print_error(error,MYF(0)); sql_print_error("%s",thd.net.last_error); + DBUG_PRINT("error", ("HA_EXTRA_NO_CACHE failed after loop")); goto err; } query_cache_invalidate3(&thd, table, 1); @@ -2248,13 +2302,16 @@ bool delayed_insert::handle_inserts(void) DBUG_RETURN(0); err: + DBUG_EXECUTE("error", max_rows= 0;); /* Remove all not used rows */ while ((row=rows.get())) { delete row; thread_safe_increment(delayed_insert_errors,&LOCK_delayed_status); stacked_inserts--; + DBUG_EXECUTE("error", max_rows++;); } + DBUG_PRINT("error", ("dropped %lu rows after an error", max_rows)); thread_safe_increment(delayed_insert_errors, &LOCK_delayed_status); pthread_mutex_lock(&mutex); DBUG_RETURN(1);