From c0ebc0fb2ab02470c9e715386e3dd32db8c33114 Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/april.(none)" <> Date: Wed, 20 Sep 2006 01:40:59 +0500 Subject: [PATCH 01/15] BUG#10974 - No error message if merge table based on union of innodb, memory Fixed confusing error message from the storage engine when it fails to open underlying table. The error message is issued when a table is _opened_ (not when it is created). --- myisammrg/myrg_open.c | 3 +++ mysql-test/r/merge.result | 13 +++++++++++-- mysql-test/r/repair.result | 2 +- mysql-test/t/merge.test | 18 ++++++++++++++++-- sql/share/english/errmsg.txt | 2 +- sql/table.cc | 9 ++++++++- 6 files changed, 40 insertions(+), 7 deletions(-) diff --git a/myisammrg/myrg_open.c b/myisammrg/myrg_open.c index f9cdc2bb205..124d37904a6 100644 --- a/myisammrg/myrg_open.c +++ b/myisammrg/myrg_open.c @@ -89,7 +89,10 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) else fn_format(buff, buff, "", "", 0); if (!(isam=mi_open(buff,mode,(handle_locking?HA_OPEN_WAIT_IF_LOCKED:0)))) + { + my_errno= HA_ERR_WRONG_MRG_TABLE_DEF; goto err; + } if (!m_info) /* First file */ { key_parts=isam->s->base.key_parts; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 038ea43cabc..2d0ca55c74a 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -178,9 +178,9 @@ t3 CREATE TABLE `t3` ( ) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t1`,`t2`) create table t4 (a int not null, b char(10), key(a)) engine=MERGE UNION=(t1,t2); select * from t4; -ERROR HY000: Can't open file: 't4.MRG' (errno: 143) +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exists alter table t4 add column c int; -ERROR HY000: Can't open file: 't4.MRG' (errno: 143) +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exists create database mysqltest; create table mysqltest.t6 (a int not null primary key auto_increment, message char(20)); create table t5 (a int not null, b char(20), key(a)) engine=MERGE UNION=(test.t1,mysqltest.t6); @@ -766,3 +766,12 @@ Table Op Msg_type Msg_text test.t1 check status OK test.t2 check status OK drop table t1, t2, t3; +CREATE TABLE t1(a INT) ENGINE=MEMORY; +CREATE TABLE t2(a INT) ENGINE=MERGE UNION=(t1); +SELECT * FROM t2; +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exists +DROP TABLE t1, t2; +CREATE TABLE t2(a INT) ENGINE=MERGE UNION=(t3); +SELECT * FROM t2; +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exists +DROP TABLE t2; diff --git a/mysql-test/r/repair.result b/mysql-test/r/repair.result index e0849452399..c069824e9f0 100644 --- a/mysql-test/r/repair.result +++ b/mysql-test/r/repair.result @@ -31,7 +31,7 @@ create table t1 engine=myisam SELECT 1,"table 1"; flush tables; repair table t1; Table Op Msg_type Msg_text -test.t1 repair error Can't open file: 't1.MYI' (errno: 130) +test.t1 repair error Got error 130 from storage engine repair table t1 use_frm; Table Op Msg_type Msg_text test.t1 repair warning Number of rows changed from 0 to 1 diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index a723443b395..93eda3aad82 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -47,9 +47,9 @@ show create table t3; # The following should give errors create table t4 (a int not null, b char(10), key(a)) engine=MERGE UNION=(t1,t2); ---error 1016 +--error 1168 select * from t4; ---error 1016 +--error 1168 alter table t4 add column c int; # @@ -376,4 +376,18 @@ select * from t3; check table t1, t2; drop table t1, t2, t3; +# +# BUG#10974 - No error message if merge table based on union of innodb, +# memory +# +CREATE TABLE t1(a INT) ENGINE=MEMORY; +CREATE TABLE t2(a INT) ENGINE=MERGE UNION=(t1); +--error 1168 +SELECT * FROM t2; +DROP TABLE t1, t2; +CREATE TABLE t2(a INT) ENGINE=MERGE UNION=(t3); +--error 1168 +SELECT * FROM t2; +DROP TABLE t2; + # End of 4.1 tests diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 300f3c6edfd..a8b06a07218 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -184,7 +184,7 @@ character-set=latin1 "INSERT DELAYED can't be used with table '%-.64s' because it is locked with LOCK TABLES", "Incorrect column name '%-.100s'", "The used storage engine can't index column '%-.64s'", -"All tables in the MERGE table are not identically defined", +"Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exists", "Can't write, because of unique constraint, to table '%-.64s'", "BLOB/TEXT column '%-.64s' used in key specification without a key length", "All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead", diff --git a/sql/table.cc b/sql/table.cc index 7587531b2f9..7680c1ff7c0 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -77,6 +77,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, my_string record; const char **int_array; bool use_hash, null_field_first; + bool error_reported= FALSE; File file; Field **field_ptr,*reg_field; KEY *keyinfo; @@ -791,6 +792,11 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, error= 1; my_errno= ENOENT; } + else + { + outparam->file->print_error(err, MYF(0)); + error_reported= TRUE; + } goto err_not_open; /* purecov: inspected */ } } @@ -812,7 +818,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, err_end: /* Here when no file */ delete crypted; *root_ptr= old_root; - frm_error(error, outparam, name, ME_ERROR + ME_WAITTANG, errarg); + if (!error_reported) + frm_error(error, outparam, name, ME_ERROR + ME_WAITTANG, errarg); delete outparam->file; outparam->file=0; // For easyer errorchecking outparam->db_stat=0; From e9e58c668222995580821ef51f28266726d29f00 Mon Sep 17 00:00:00 2001 From: "istruewing@chilla.local" <> Date: Wed, 20 Sep 2006 11:05:11 +0200 Subject: [PATCH 02/15] Bug#20830 - INSERT DELAYED does not honour SET INSERT_ID Bug#20627 - INSERT DELAYED does not honour auto_increment_* variables INSERT DELAYED ignored an explicitly set INSERT_ID and session specific auto_increment_* variables. The problem was that the inserts are done by a system thread, which does not have access to the session variables of the user thread. On a proposal of Guilhem I fixed it so that the variables are copied to the data structure for every delayed row. The system thread sets its session variables from these values. --- mysql-test/r/delayed.result | 174 ++++++++++++++++++++++++++++++++++++ mysql-test/t/delayed.test | 148 ++++++++++++++++++++++++++++-- sql/sql_insert.cc | 46 ++++++++++ 3 files changed, 362 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/delayed.result b/mysql-test/r/delayed.result index a336f3b4108..6295fceec2b 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 1 +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 eaa7d3a72db..e3aecbaace2 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1274,6 +1274,9 @@ public: time_t start_time; bool query_start_used,last_insert_id_used,insert_id_used, ignore, log_query; ulonglong last_insert_id; + ulonglong next_insert_id; + ulong auto_increment_increment; + ulong auto_increment_offset; timestamp_auto_set_type timestamp_field_type; uint query_length; @@ -1655,6 +1658,22 @@ static int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic, bool igno row->last_insert_id= thd->last_insert_id; row->timestamp_field_type= table->timestamp_field_type; + /* The session variable settings can always be copied. */ + 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; + di->rows.push_back(row); di->stacked_inserts++; di->status=1; @@ -2026,6 +2045,14 @@ bool delayed_insert::handle_inserts(void) thd.insert_id_used=row->insert_id_used; table->timestamp_field_type= row->timestamp_field_type; + /* The session variable settings can always be copied. */ + 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)); + info.ignore= row->ignore; info.handle_duplicates= row->dup; if (info.ignore || @@ -2047,6 +2074,20 @@ 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) { @@ -2092,6 +2133,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); @@ -2117,6 +2159,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); @@ -2124,13 +2167,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); From 1306e65a0a44f1f07c9bc01006c5360941fc5d2f Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/april.(none)" <> Date: Wed, 20 Sep 2006 17:12:37 +0500 Subject: [PATCH 03/15] BUG#21459 - myisam_ftdump gives bad counts for common words This problem affects myisam_ftdump tool only. For fulltext index positive subkeys means word weight, negative subkeys means number of documents in level 2 fulltext index. Fixed that document counter was not properly updated for keys having level 2 fulltext index. No test case for this bug. --- myisam/myisam_ftdump.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/myisam/myisam_ftdump.c b/myisam/myisam_ftdump.c index 809d7bcca89..2be95d11714 100644 --- a/myisam/myisam_ftdump.c +++ b/myisam/myisam_ftdump.c @@ -126,7 +126,6 @@ int main(int argc,char *argv[]) if (count || stats) { - doc_cnt++; if (strcmp(buf, buf2)) { if (*buf2) @@ -151,6 +150,7 @@ int main(int argc,char *argv[]) keylen2=keylen; doc_cnt=0; } + doc_cnt+= (subkeys >= 0 ? 1 : -subkeys); } if (dump) { @@ -166,7 +166,6 @@ int main(int argc,char *argv[]) if (count || stats) { - doc_cnt++; if (*buf2) { uniq++; From 2b121cd0e1269a18765413a5e54ccfd35fbdfa4d Mon Sep 17 00:00:00 2001 From: "istruewing@chilla.local" <> Date: Fri, 22 Sep 2006 17:23:25 +0200 Subject: [PATCH 04/15] Bug#14400 - Query joins wrong rows from table which is subject of "concurrent insert" After merge fix. --- myisam/mi_rkey.c | 1 + 1 file changed, 1 insertion(+) diff --git a/myisam/mi_rkey.c b/myisam/mi_rkey.c index 52403b110cb..be99d66618d 100644 --- a/myisam/mi_rkey.c +++ b/myisam/mi_rkey.c @@ -86,6 +86,7 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, if (info->lastpos >= info->state->data_file_length && (search_flag != HA_READ_KEY_EXACT || last_used_keyseg != keyinfo->seg + keyinfo->keysegs)) + { do { uint not_used; From 6414330377717dbc73564acec7eeebddc7ab28df Mon Sep 17 00:00:00 2001 From: "acurtis/antony@xiphis.org/ltamd64.xiphis.org" <> Date: Mon, 25 Sep 2006 10:59:49 -0700 Subject: [PATCH 05/15] Bug#21610 "Loaded engine does not load after restart." Junk characters caused plugin load to fail silently. --- sql/sql_plugin.cc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 97c28dd1fa5..1a3626acaf6 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -759,14 +759,16 @@ void plugin_load(void) while (!(error= read_record_info.read_record(&read_record_info))) { DBUG_PRINT("info", ("init plugin record")); - LEX_STRING name, dl; - name.str= get_field(&mem, table->field[0]); - name.length= strlen(name.str); - dl.str= get_field(&mem, table->field[1]); - dl.length= strlen(dl.str); + String str_name, str_dl; + get_field(&mem, table->field[0], &str_name); + get_field(&mem, table->field[1], &str_dl); + + LEX_STRING name= {(char *)str_name.ptr(), str_name.length()}; + LEX_STRING dl= {(char *)str_dl.ptr(), str_dl.length()}; + if (plugin_add(&name, &dl, REPORT_TO_LOG)) - DBUG_PRINT("warning", ("Couldn't load plugin named '%s' with soname '%s'.", - name.str, dl.str)); + sql_print_warning("Couldn't load plugin named '%s' with soname '%s'.", + str_name.c_ptr(), str_dl.c_ptr()); } if (error > 0) sql_print_error(ER(ER_GET_ERRNO), my_errno); From 5f14652ef5039138f1f2f69f1edcd8c647150f9e Mon Sep 17 00:00:00 2001 From: "acurtis/antony@xiphis.org/ltamd64.xiphis.org" <> Date: Mon, 25 Sep 2006 11:48:51 -0700 Subject: [PATCH 06/15] Bug#20615 "plugin name lost when loading an already-loaded name" Do not delete existing plugin when loading a new plugin which has the same name. --- sql/sql_plugin.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 1a3626acaf6..34fb447792e 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -864,8 +864,8 @@ my_bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING DBUG_RETURN(FALSE); deinit: plugin_deinitialize(tmp); -err: plugin_del(tmp); +err: rw_unlock(&THR_LOCK_plugin); DBUG_RETURN(TRUE); } From ac778232cd364483af2d5fe1f50fbdebbd582698 Mon Sep 17 00:00:00 2001 From: "istruewing@chilla.local" <> Date: Wed, 27 Sep 2006 11:55:30 +0200 Subject: [PATCH 07/15] Bug#20719 - Reading dynamic records with write buffer could fail After merge fix. --- myisam/mi_dynrec.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c index e2d24ccb39e..4dec3055fa1 100644 --- a/myisam/mi_dynrec.c +++ b/myisam/mi_dynrec.c @@ -1148,9 +1148,6 @@ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf) info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH && flush_io_cache(&info->rec_cache)) goto err; - /* A corrupted table can have wrong pointers. (Bug# 19835) */ - if (block_info.next_filepos == HA_OFFSET_ERROR) - goto panic; info->rec_cache.seek_not_done=1; if ((b_type= _mi_get_block_info(&block_info, file, filepos)) & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | From b724a03e088ba748e3f13a03558d781f66e2e3bb Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/april.(none)" <> Date: Wed, 27 Sep 2006 18:33:31 +0500 Subject: [PATCH 08/15] After merge fix. --- mysql-test/r/merge.result | 18 +++++++++--------- sql/share/errmsg.txt | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 50d392725e4..0e4cabc62e0 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -768,6 +768,15 @@ Table Op Msg_type Msg_text test.t1 check status OK test.t2 check status OK drop table t1, t2, t3; +CREATE TABLE t1(a INT) ENGINE=MEMORY; +CREATE TABLE t2(a INT) ENGINE=MERGE UNION=(t1); +SELECT * FROM t2; +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exists +DROP TABLE t1, t2; +CREATE TABLE t2(a INT) ENGINE=MERGE UNION=(t3); +SELECT * FROM t2; +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exists +DROP TABLE t2; create table t1 (b bit(1)); create table t2 (b bit(1)); create table tm (b bit(1)) engine = merge union = (t1,t2); @@ -785,13 +794,4 @@ insert into t1 values (1); ERROR HY000: Table 't1' is read only drop table t2; drop table t1; -CREATE TABLE t1(a INT) ENGINE=MEMORY; -CREATE TABLE t2(a INT) ENGINE=MERGE UNION=(t1); -SELECT * FROM t2; -ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exists -DROP TABLE t1, t2; -CREATE TABLE t2(a INT) ENGINE=MERGE UNION=(t3); -SELECT * FROM t2; -ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exists -DROP TABLE t2; End of 5.0 tests diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 05b31b1e8b2..a097b438fe0 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -3813,7 +3813,7 @@ ER_WRONG_MRG_TABLE cze "V-B¹echny tabulky v MERGE tabulce nejsou definovány stejnì" dan "Tabellerne i MERGE er ikke defineret ens" nla "Niet alle tabellen in de MERGE tabel hebben identieke gedefinities" - eng "All tables in the MERGE table are not identically defined" + eng "Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exists" est "Kõik tabelid MERGE tabeli määratluses ei ole identsed" fre "Toutes les tables de la table de type MERGE n'ont pas la même définition" ger "Nicht alle Tabellen in der MERGE-Tabelle sind gleich definiert" From 4027fc8dca26ae421510af32fdefa90e5ec492bb Mon Sep 17 00:00:00 2001 From: "istruewing@chilla.local" <> Date: Thu, 28 Sep 2006 11:41:38 +0200 Subject: [PATCH 09/15] Bug#22384 - DELETE FROM table causes "Incorrect key file for table" Deletes on a big index could crash the index when it needs to shrink. Put a forgotten negation operator in. No test case. It is too big for the test suite. And it does not work with 4.0, only with higher versions. It is attached to the bug report. --- myisam/mi_delete.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c index 6f94e3c4256..2c7e2b28a3d 100644 --- a/myisam/mi_delete.c +++ b/myisam/mi_delete.c @@ -348,7 +348,7 @@ static int del(register MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *key, else { DBUG_PRINT("test",("Inserting of key when deleting")); - if (_mi_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos, + if (!_mi_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos, &tmp)) goto err; ret_value=_mi_insert(info,keyinfo,key,leaf_buff,endpos,keybuff, From efb75811bf77dfd078105e353677a37a8ecaf5e1 Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/april.(none)" <> Date: Thu, 28 Sep 2006 20:30:15 +0500 Subject: [PATCH 10/15] BUG#21675 - engine=archive 2GB file limit, when reached mysqld restarts on any query If mysqld is linked against system installed zlib (which is likely compiled w/o LFS) and archive table exceedes 2G, mysqld will likely be terminated with SIGXFSZ. Prior to actual write perform a check if there is space in data file. This fixes abnormal process termination with SIGXFSZ. No test case for this bugfix. --- sql/ha_archive.cc | 24 ++++++++++++++++++++---- sql/ha_archive.h | 1 + 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc index 3885defb4d5..de32f9b1fa4 100644 --- a/sql/ha_archive.cc +++ b/sql/ha_archive.cc @@ -120,6 +120,8 @@ static bool archive_inited= FALSE; /* Variables for archive share methods */ pthread_mutex_t archive_mutex; static HASH archive_open_tables; +static z_off_t max_zfile_size; +static int zoffset_size; /* The file extension */ #define ARZ ".ARZ" // The data file @@ -203,6 +205,8 @@ bool archive_db_init() } else { + zoffset_size= 2 << ((zlibCompileFlags() >> 6) & 3); + max_zfile_size= (z_off_t) (~(1 << (zoffset_size * 8 - 1))); archive_inited= TRUE; DBUG_RETURN(FALSE); } @@ -240,7 +244,7 @@ ha_archive::ha_archive(TABLE *table_arg) buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info); /* The size of the offset value we will use for position() */ - ref_length = 2 << ((zlibCompileFlags() >> 6) & 3); + ref_length = zoffset_size; DBUG_ASSERT(ref_length <= sizeof(z_off_t)); } @@ -480,7 +484,8 @@ int ha_archive::init_archive_writer() DBUG_RETURN(1); } share->archive_write_open= TRUE; - + info(HA_STATUS_TIME); + share->approx_file_size= data_file_length; DBUG_RETURN(0); } @@ -651,10 +656,21 @@ error: */ int ha_archive::real_write_row(byte *buf, gzFile writer) { - z_off_t written; + z_off_t written, total_row_length; uint *ptr, *end; DBUG_ENTER("ha_archive::real_write_row"); - + total_row_length= table->s->reclength; + for (ptr= table->s->blob_field, end= ptr + table->s->blob_fields; + ptr != end; ptr++) + total_row_length+= ((Field_blob*) table->field[*ptr])->get_length(); + if (share->approx_file_size > max_zfile_size - total_row_length) + { + info(HA_STATUS_TIME); + share->approx_file_size= data_file_length; + if (share->approx_file_size > max_zfile_size - total_row_length) + DBUG_RETURN(HA_ERR_RECORD_FILE_FULL); + } + share->approx_file_size+= total_row_length; written= gzwrite(writer, buf, table->s->reclength); DBUG_PRINT("ha_archive::real_write_row", ("Wrote %d bytes expected %d", written, table->s->reclength)); if (!delayed_insert || !bulk_insert) diff --git a/sql/ha_archive.h b/sql/ha_archive.h index 2bac9fa605e..564b9f03bf5 100644 --- a/sql/ha_archive.h +++ b/sql/ha_archive.h @@ -38,6 +38,7 @@ typedef struct st_archive_share { bool dirty; /* Flag for if a flush should occur */ bool crashed; /* Meta file is crashed */ ha_rows rows_recorded; /* Number of rows in tables */ + z_off_t approx_file_size; /* Approximate archive data file size */ } ARCHIVE_SHARE; /* From b271d7653bcea54865e14d9dac52cf126ad97fcf Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/april.(none)" <> Date: Thu, 28 Sep 2006 22:10:06 +0500 Subject: [PATCH 11/15] BUG#21617 - crash when selecting from merge table with inconsistent indexes Crash may happen when selecting from a merge table that has underlying tables with less indexes than in a merge table itself. If number of keys in merge table is not bigger than requested key number, return error. --- myisammrg/myrg_open.c | 7 ++++-- myisammrg/myrg_queue.c | 2 ++ mysql-test/r/merge.result | 6 +++++ mysql-test/t/merge.test | 11 +++++++++ mysys/queues.c | 48 ++++++++++++++++----------------------- 5 files changed, 43 insertions(+), 31 deletions(-) diff --git a/myisammrg/myrg_open.c b/myisammrg/myrg_open.c index f9cdc2bb205..6527ac648f7 100644 --- a/myisammrg/myrg_open.c +++ b/myisammrg/myrg_open.c @@ -33,7 +33,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) { int save_errno,errpos=0; - uint files=0,i,dir_length,length,key_parts; + uint files= 0, i, dir_length, length, key_parts, min_keys= 0; ulonglong file_offset=0; char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end; MYRG_INFO *m_info=0; @@ -106,6 +106,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) files= 0; } m_info->reclength=isam->s->base.reclength; + min_keys= isam->s->base.keys; errpos=3; } m_info->open_tables[files].table= isam; @@ -121,6 +122,8 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) m_info->records+= isam->state->records; m_info->del+= isam->state->del; m_info->data_file_length+= isam->state->data_file_length; + if (min_keys > isam->s->base.keys) + min_keys= isam->s->base.keys; for (i=0; i < key_parts; i++) m_info->rec_per_key_part[i]+= (isam->s->state.rec_per_key_part[i] / m_info->tables); @@ -138,7 +141,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) my_errno=HA_ERR_RECORD_FILE_FULL; goto err; } - m_info->keys= files ? isam->s->base.keys : 0; + m_info->keys= min_keys; bzero((char*) &m_info->by_key,sizeof(m_info->by_key)); /* this works ok if the table list is empty */ diff --git a/myisammrg/myrg_queue.c b/myisammrg/myrg_queue.c index 7172b9f0e2a..bf99e8434a6 100644 --- a/myisammrg/myrg_queue.c +++ b/myisammrg/myrg_queue.c @@ -51,6 +51,8 @@ int _myrg_init_queue(MYRG_INFO *info,int inx,enum ha_rkey_function search_flag) error=my_errno; } } + else + my_errno= error= HA_ERR_WRONG_INDEX; return error; } diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 038ea43cabc..bd9be0ae8b2 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -766,3 +766,9 @@ Table Op Msg_type Msg_text test.t1 check status OK test.t2 check status OK drop table t1, t2, t3; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES(2),(1); +CREATE TABLE t2(a INT, KEY(a)) ENGINE=MERGE UNION=(t1); +SELECT * FROM t2 WHERE a=2; +ERROR HY000: Got error 124 from storage engine +DROP TABLE t1, t2; diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index a723443b395..219a33d344b 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -376,4 +376,15 @@ select * from t3; check table t1, t2; drop table t1, t2, t3; +# +# BUG#21617 - crash when selecting from merge table with inconsistent +# indexes +# +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES(2),(1); +CREATE TABLE t2(a INT, KEY(a)) ENGINE=MERGE UNION=(t1); +--error 1030 +SELECT * FROM t2 WHERE a=2; +DROP TABLE t1, t2; + # End of 4.1 tests diff --git a/mysys/queues.c b/mysys/queues.c index ecf1058af41..6a285ce7417 100644 --- a/mysys/queues.c +++ b/mysys/queues.c @@ -164,28 +164,22 @@ void delete_queue(QUEUE *queue) void queue_insert(register QUEUE *queue, byte *element) { - reg2 uint idx,next; + reg2 uint idx, next; int cmp; - -#ifndef DBUG_OFF - if (queue->elements < queue->max_elements) -#endif + DBUG_ASSERT(queue->elements < queue->max_elements); + queue->root[0]= element; + idx= ++queue->elements; + /* max_at_top swaps the comparison if we want to order by desc */ + while ((cmp= queue->compare(queue->first_cmp_arg, + element + queue->offset_to_key, + queue->root[(next= idx >> 1)] + + queue->offset_to_key)) && + (cmp ^ queue->max_at_top) < 0) { - queue->root[0]=element; - idx= ++queue->elements; - - /* max_at_top swaps the comparison if we want to order by desc */ - while ((cmp=queue->compare(queue->first_cmp_arg, - element+queue->offset_to_key, - queue->root[(next=idx >> 1)] + - queue->offset_to_key)) && - (cmp ^ queue->max_at_top) < 0) - { - queue->root[idx]=queue->root[next]; - idx=next; - } - queue->root[idx]=element; + queue->root[idx]= queue->root[next]; + idx= next; } + queue->root[idx]= element; } /* Remove item from queue */ @@ -193,16 +187,12 @@ void queue_insert(register QUEUE *queue, byte *element) byte *queue_remove(register QUEUE *queue, uint idx) { -#ifndef DBUG_OFF - if (idx >= queue->max_elements) - return 0; -#endif - { - byte *element=queue->root[++idx]; /* Intern index starts from 1 */ - queue->root[idx]=queue->root[queue->elements--]; - _downheap(queue,idx); - return element; - } + byte *element; + DBUG_ASSERT(idx < queue->max_elements); + element= queue->root[++idx]; /* Intern index starts from 1 */ + queue->root[idx]= queue->root[queue->elements--]; + _downheap(queue, idx); + return element; } /* Fix when element on top has been replaced */ From 15d330ebcea124c429fe2b37d585d09852258ee4 Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/april.(none)" <> Date: Fri, 29 Sep 2006 01:36:17 +0500 Subject: [PATCH 12/15] After merge fix. --- mysql-test/r/merge.result | 2 +- mysql-test/t/merge.test | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index b08b985983d..f9c2f111734 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -277,7 +277,7 @@ t3 CREATE TABLE `t3` ( drop table t3,t2,t1; create table t1 (a int not null, key(a)) engine=merge; select * from t1; -a +ERROR HY000: Got error 124 from storage engine drop table t1; create table t1 (a int not null, b int not null, key(a,b)); create table t2 (a int not null, b int not null, key(a,b)); diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index 4006fa27fe3..5498468d902 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -124,6 +124,7 @@ drop table t3,t2,t1; # Test table without unions # create table t1 (a int not null, key(a)) engine=merge; +--error 1030 select * from t1; drop table t1; From 8148bf497a01a9dc43544f22e6e255699e43e318 Mon Sep 17 00:00:00 2001 From: "istruewing@chilla.local" <> Date: Fri, 29 Sep 2006 13:23:33 +0200 Subject: [PATCH 13/15] 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 | 2 +- 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 From 0297046a105a0e23b06a13898f0625a7a78624cd Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/april.(none)" <> Date: Fri, 29 Sep 2006 19:00:52 +0500 Subject: [PATCH 14/15] Fix a test case according to fix for bug#10974. --- mysql-test/r/lowercase_table3.result | 2 +- mysql-test/t/lowercase_table3.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/lowercase_table3.result b/mysql-test/r/lowercase_table3.result index 8182d07c26b..2c31936f89e 100644 --- a/mysql-test/r/lowercase_table3.result +++ b/mysql-test/r/lowercase_table3.result @@ -6,5 +6,5 @@ drop table t1; flush tables; CREATE TABLE t1 (a int) ENGINE=INNODB; SELECT * from T1; -ERROR HY000: Can't open file: 'T1.ibd' (errno: 1) +ERROR HY000: Got error 1 from storage engine drop table t1; diff --git a/mysql-test/t/lowercase_table3.test b/mysql-test/t/lowercase_table3.test index 9208f3a76ec..549bd7d8045 100644 --- a/mysql-test/t/lowercase_table3.test +++ b/mysql-test/t/lowercase_table3.test @@ -32,7 +32,7 @@ flush tables; # CREATE TABLE t1 (a int) ENGINE=INNODB; ---error 1016 +--error 1030 SELECT * from T1; drop table t1; From deaf47083962137a8fc1a45b7fade5b0ec334098 Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/april.(none)" <> Date: Fri, 29 Sep 2006 21:36:17 +0500 Subject: [PATCH 15/15] Fixed that max_zfile_size was incorrectly calculated on big-endian boxes. Was introduced with patch for bug#21675. --- sql/ha_archive.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc index 3a30f404a40..bc3c819c4ed 100644 --- a/sql/ha_archive.cc +++ b/sql/ha_archive.cc @@ -206,7 +206,17 @@ bool archive_db_init() else { zoffset_size= 2 << ((zlibCompileFlags() >> 6) & 3); - max_zfile_size= (z_off_t) (~(1 << (zoffset_size * 8 - 1))); + switch (sizeof(z_off_t)) { + case 2: + max_zfile_size= INT_MAX16; + break; + case 8: + max_zfile_size= LONGLONG_MAX; + break; + case 4: + default: + max_zfile_size= INT_MAX32; + } archive_inited= TRUE; DBUG_RETURN(FALSE); }