List:Commits« Previous MessageNext Message »
From:ingo Date:September 26 2006 5:43pm
Subject:bk commit into 5.1 tree (istruewing:1.2338) BUG#20627
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of istruewing. When istruewing does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2006-09-26 17:43:06+02:00, istruewing@stripped +3 -0
  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.
  Added start-of-new-statement detection for releasing the
  auto_increment values. This aligns the behaviour of delayed
  inserts to non-delayed inserts.

  mysql-test/r/delayed.result@stripped, 2006-09-26 17:43:02+02:00, istruewing@stripped +57
-9
    Bug#20830 - INSERT DELAYED does not honour SET INSERT_ID
    Bug#20627 - INSERT DELAYED does not honour auto_increment_* variables
    Merge from 5.0.
    Additional test results.

  mysql-test/t/delayed.test@stripped, 2006-09-26 17:43:02+02:00, istruewing@stripped +58
-4
    Bug#20830 - INSERT DELAYED does not honour SET INSERT_ID
    Bug#20627 - INSERT DELAYED does not honour auto_increment_* variables
    Merge from 5.0.
    Additional tests.

  sql/sql_insert.cc@stripped, 2006-09-26 17:43:02+02:00, istruewing@stripped +66 -33
    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.
    Added start-of-new-statement detection for releasing the
    auto_increment values. This aligns the behaviour of delayed
    inserts to non-delayed inserts.

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	istruewing
# Host:	chilla.local
# Root:	/home/mydev/mysql-5.1-bug20627

--- 1.225/sql/sql_insert.cc	2006-09-26 17:43:13 +02:00
+++ 1.226/sql/sql_insert.cc	2006-09-26 17:43:13 +02:00
@@ -1330,7 +1330,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 +1339,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()
   {
@@ -1358,6 +1358,7 @@ public:
   pthread_cond_t cond,cond_client;
   volatile uint tables_in_use,stacked_inserts;
   volatile bool status,dead;
+  bool error_in_statement;      // be able to ignore values after an error
   COPY_INFO info;
   I_List<delayed_row> rows;
   ulong group_count;
@@ -1366,7 +1367,7 @@ public:
   delayed_insert()
     :locks_in_memory(0),
      table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0),
-     group_count(0)
+     error_in_statement(0), group_count(0)
   {
     thd.security_ctx->user=thd.security_ctx->priv_user=(char*) delayed_user;
     thd.security_ctx->host=(char*) my_localhost;
@@ -1697,6 +1698,7 @@ write_delayed(THD *thd,TABLE *table, enu
 {
   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 +1748,16 @@ write_delayed(THD *thd,TABLE *table, enu
     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 +2010,10 @@ pthread_handler_t handle_delayed_insert(
       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;
@@ -2141,13 +2142,52 @@ bool delayed_insert::handle_inserts(void
       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. */
+    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();
+      /*
+        Reinitialize the ignore-values-flag for a new statement. See
+        below for a detailed description.
+      */
+      error_in_statement= FALSE;
+    }
+    if (error_in_statement)
+    {
+      /*
+        There was an insert error for a former value of the same
+        statement. Behave like non-delayed insert does. Abort the
+        statement. Or ignore all following values, which comes to the
+        same effect. But we still need to take all values from the
+        queue. And since the values from one statement can appear in the
+        delayed insert thread in several chunks, error_in_statement is a
+        variable in the delayed_insert object and as such survives
+        several calls of delayed_insert::handle_inserts().
+      */
+      pthread_mutex_lock(&mutex);
+      delete row;
+      continue;
+    }
+
+    /* 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;
@@ -2171,19 +2211,12 @@ bool delayed_insert::handle_inserts(void
       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.
+        Non-delayed (and non-ignored) insert aborts a statement after an
+        error. Simulate this here by setting the error_in_statement
+        flag. See above for a detailed description. The distinction
+        between ignored and non-ignored is done within write_record().
       */
-      thd.next_insert_id= 0;
+      error_in_statement= TRUE;
     }
 
     if (using_ignore)

--- 1.12/mysql-test/r/delayed.result	2006-09-26 17:43:13 +02:00
+++ 1.13/mysql-test/r/delayed.result	2006-09-26 17:43:13 +02:00
@@ -130,7 +130,8 @@ SET @@session.auto_increment_increment= 
 CREATE TABLE t1 (
 c1 INT(11) NOT NULL AUTO_INCREMENT,
 c2 INT(11) DEFAULT NULL,
-PRIMARY KEY (c1)
+PRIMARY KEY (c1),
+UNIQUE INDEX (c2)
 );
 SET insert_id= 14;
 INSERT INTO t1 VALUES(NULL, 11), (NULL, 12), (NULL, 13);
@@ -144,8 +145,24 @@ INSERT INTO t1 VALUES(  49, 71), (NULL, 
 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);
+ERROR 23000: Duplicate entry '114' for key 'PRIMARY'
+INSERT INTO t1 VALUES            (NULL, 92), (NULL, 93);
+SET insert_id= 174;
+INSERT INTO t1 VALUES(NULL, 111), (NULL, 112), (NULL, 113);
+ERROR 23000: Duplicate entry '174' for key 'PRIMARY'
+INSERT INTO t1 VALUES(NULL, 121), (174,  122), (NULL, 123);
+ERROR 23000: Duplicate entry '174' for key 'PRIMARY'
+INSERT INTO t1 VALUES(NULL,  11), (NULL, 132), (NULL, 133);
+ERROR 23000: Duplicate entry '11' for key 'c2'
+INSERT INTO t1 VALUES(NULL, 141), (NULL,  11), (NULL, 143);
+ERROR 23000: Duplicate entry '11' for key 'c2'
+SET insert_id= 184;
+INSERT IGNORE INTO t1 VALUES(NULL, 151), (NULL, 152), (NULL, 153);
+INSERT IGNORE INTO t1 VALUES(NULL, 161), (189,  162), (NULL, 163);
+INSERT IGNORE INTO t1 VALUES(NULL,  11), (NULL, 172), (NULL, 173);
+INSERT IGNORE INTO t1 VALUES(NULL, 181), (NULL,  11), (NULL, 183);
+SET insert_id= 44;
+INSERT IGNORE INTO t1 VALUES(NULL, 191), (NULL, 192), (NULL, 193);
 SELECT * FROM t1;
 c1	c2
 14	11
@@ -174,17 +191,27 @@ c1	c2
 164	83
 169	92
 174	93
+179	121
+184	141
+189	161
+194	163
+199	172
+204	173
+209	181
+214	183
+44	191
 SELECT COUNT(*) FROM t1;
 COUNT(*)
-26
+35
 SELECT SUM(c1) FROM t1;
 SUM(c1)
-2569
+4185
 DROP TABLE t1;
 CREATE TABLE t1 (
 c1 INT(11) NOT NULL AUTO_INCREMENT,
 c2 INT(11) DEFAULT NULL,
-PRIMARY KEY (c1)
+PRIMARY KEY (c1),
+UNIQUE INDEX (c2)
 );
 SET insert_id= 14;
 INSERT DELAYED INTO t1 VALUES(NULL, 11), (NULL, 12), (NULL, 13);
@@ -198,7 +225,19 @@ INSERT DELAYED INTO t1 VALUES(  49, 71),
 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);
+INSERT DELAYED INTO t1 VALUES            (NULL, 92), (NULL, 93);
+SET insert_id= 174;
+INSERT DELAYED INTO t1 VALUES(NULL, 111), (NULL, 112), (NULL, 113);
+INSERT DELAYED INTO t1 VALUES(NULL, 121), (174,  122), (NULL, 123);
+INSERT DELAYED INTO t1 VALUES(NULL,  11), (NULL, 132), (NULL, 133);
+INSERT DELAYED INTO t1 VALUES(NULL, 141), (NULL,  11), (NULL, 143);
+SET insert_id= 184;
+INSERT DELAYED IGNORE INTO t1 VALUES(NULL, 151), (NULL, 152), (NULL, 153);
+INSERT DELAYED IGNORE INTO t1 VALUES(NULL, 161), (189,  162), (NULL, 163);
+INSERT DELAYED IGNORE INTO t1 VALUES(NULL,  11), (NULL, 172), (NULL, 173);
+INSERT DELAYED IGNORE INTO t1 VALUES(NULL, 181), (NULL,  11), (NULL, 183);
+SET insert_id= 44;
+INSERT DELAYED IGNORE INTO t1 VALUES(NULL, 191), (NULL, 192), (NULL, 193);
 FLUSH TABLE t1;
 SELECT * FROM t1;
 c1	c2
@@ -228,12 +267,21 @@ c1	c2
 164	83
 169	92
 174	93
+179	121
+184	141
+189	161
+194	163
+199	172
+204	173
+209	181
+214	183
+44	191
 SELECT COUNT(*) FROM t1;
 COUNT(*)
-26
+35
 SELECT SUM(c1) FROM t1;
 SUM(c1)
-2569
+4185
 DROP TABLE t1;
 SET             @@auto_increment_offset=
 @bug20830_old_auto_increment_offset;

--- 1.15/mysql-test/t/delayed.test	2006-09-26 17:43:13 +02:00
+++ 1.16/mysql-test/t/delayed.test	2006-09-26 17:43:13 +02:00
@@ -168,7 +168,8 @@ SET @@session.auto_increment_increment= 
 CREATE TABLE t1 (
   c1 INT(11) NOT NULL AUTO_INCREMENT,
   c2 INT(11) DEFAULT NULL,
-  PRIMARY KEY (c1)
+  PRIMARY KEY (c1),
+  UNIQUE INDEX (c2)
   );
 SET insert_id= 14;
 INSERT INTO t1 VALUES(NULL, 11), (NULL, 12), (NULL, 13);
@@ -187,7 +188,35 @@ INSERT INTO t1 VALUES(NULL, 81), (NULL, 
 SET insert_id= 114;
 --error 1062
 INSERT INTO t1 VALUES(NULL, 91);
-INSERT INTO t1 VALUES           (NULL, 92), (NULL, 93);
+INSERT INTO t1 VALUES            (NULL, 92), (NULL, 93);
+#
+# Create a duplicate value at begin of statement.
+SET insert_id= 174;
+--error 1062
+INSERT INTO t1 VALUES(NULL, 111), (NULL, 112), (NULL, 113);
+# Create a duplicate value in middle of statement.
+--error 1062
+INSERT INTO t1 VALUES(NULL, 121), (174,  122), (NULL, 123);
+# Create a duplicate value in non-auto index at begin of statement.
+--error 1062
+INSERT INTO t1 VALUES(NULL,  11), (NULL, 132), (NULL, 133);
+# Create a duplicate value in non-auto index in middle of statement.
+--error 1062
+INSERT INTO t1 VALUES(NULL, 141), (NULL,  11), (NULL, 143);
+#
+# Ignore a duplicate value at begin of statement.
+SET insert_id= 184;
+INSERT IGNORE INTO t1 VALUES(NULL, 151), (NULL, 152), (NULL, 153);
+# Ignore a duplicate value in middle of statement.
+INSERT IGNORE INTO t1 VALUES(NULL, 161), (189,  162), (NULL, 163);
+# Ignore a duplicate value in non-auto index at begin of statement.
+INSERT IGNORE INTO t1 VALUES(NULL,  11), (NULL, 172), (NULL, 173);
+# Ignore a duplicate value in non-auto index in middle of statement.
+INSERT IGNORE INTO t1 VALUES(NULL, 181), (NULL,  11), (NULL, 183);
+# Ignore a duplicate value in automatic sequence in middle of statement.
+SET insert_id= 44;
+INSERT IGNORE INTO t1 VALUES(NULL, 191), (NULL, 192), (NULL, 193);
+#
 # Check what we have now
 SELECT * FROM t1;
 SELECT COUNT(*) FROM t1;
@@ -198,7 +227,8 @@ DROP TABLE t1;
 CREATE TABLE t1 (
   c1 INT(11) NOT NULL AUTO_INCREMENT,
   c2 INT(11) DEFAULT NULL,
-  PRIMARY KEY (c1)
+  PRIMARY KEY (c1),
+  UNIQUE INDEX (c2)
   );
 SET insert_id= 14;
 INSERT DELAYED INTO t1 VALUES(NULL, 11), (NULL, 12), (NULL, 13);
@@ -216,7 +246,31 @@ INSERT DELAYED INTO t1 VALUES(NULL, 81),
 # Create a duplicate value.
 SET insert_id= 114;
 INSERT DELAYED INTO t1 VALUES(NULL, 91);
-INSERT DELAYED INTO t1 VALUES           (NULL, 92), (NULL, 93);
+INSERT DELAYED INTO t1 VALUES            (NULL, 92), (NULL, 93);
+#
+# Create a duplicate value at begin of statement.
+SET insert_id= 174;
+INSERT DELAYED INTO t1 VALUES(NULL, 111), (NULL, 112), (NULL, 113);
+# Create a duplicate value in middle of statement.
+INSERT DELAYED INTO t1 VALUES(NULL, 121), (174,  122), (NULL, 123);
+# Create a duplicate value in non-auto index at begin of statement.
+INSERT DELAYED INTO t1 VALUES(NULL,  11), (NULL, 132), (NULL, 133);
+# Create a duplicate value in non-auto index in middle of statement.
+INSERT DELAYED INTO t1 VALUES(NULL, 141), (NULL,  11), (NULL, 143);
+#
+# Ignore a duplicate value at begin of statement.
+SET insert_id= 184;
+INSERT DELAYED IGNORE INTO t1 VALUES(NULL, 151), (NULL, 152), (NULL, 153);
+# Ignore a duplicate value in middle of statement.
+INSERT DELAYED IGNORE INTO t1 VALUES(NULL, 161), (189,  162), (NULL, 163);
+# Ignore a duplicate value in non-auto index at begin of statement.
+INSERT DELAYED IGNORE INTO t1 VALUES(NULL,  11), (NULL, 172), (NULL, 173);
+# Ignore a duplicate value in non-auto index in middle of statement.
+INSERT DELAYED IGNORE INTO t1 VALUES(NULL, 181), (NULL,  11), (NULL, 183);
+# Ignore a duplicate value in automatic sequence in middle of statement.
+SET insert_id= 44;
+INSERT DELAYED IGNORE INTO t1 VALUES(NULL, 191), (NULL, 192), (NULL, 193);
+#
 # Wait until the rows are flushed to the table files.
 FLUSH TABLE t1;
 # Check what we have now
Thread
bk commit into 5.1 tree (istruewing:1.2338) BUG#20627ingo26 Sep