List:Commits« Previous MessageNext Message »
From:antony Date:June 20 2007 2:36am
Subject:bk commit into 5.0 tree (antony:1.2493) BUG#25511
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of antony. When antony 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, 2007-06-19 19:36:48-07:00, antony@stripped +4 -0
  bug#25511
    "Federated INSERT failures"
    Federated does not correctly handle "INSERT ... ON DUPLICATE KEY UPDATE"
    If an "ON DUPLICATE KEY UPDATE" is in effect while writing a row,
    we want to retieve the keynr which has failed and pass that info back.
    A match between the remote key definition and local keys is required.
    Both local and remote servers require matching PK definition.
    We detect if ON DUPLICATE KEY UPDATE is in effect by checking for
    HA_EXTRA_RETRIEVE_PRIMARY_KEY.
    This patch builds on Bug29019

  mysql-test/r/federated.result@stripped, 2007-06-19 19:36:42-07:00, antony@stripped +11 -0
    test for bug25511

  mysql-test/t/federated.test@stripped, 2007-06-19 19:36:43-07:00, antony@stripped +20 -0
    test for bug25511

  sql/ha_federated.cc@stripped, 2007-06-19 19:36:43-07:00, antony@stripped +127 -12
    bug25511
      "Federated INSERT failures"
      If an "ON DUPLICATE KEY UPDATE" is in effect while writing a row,
      we want to retieve the key which has failed and pass that info back.
      We detect if ON DUPLICATE KEY UPDATE is in effect by checking for
      HA_EXTRA_RETRIEVE_PRIMARY_KEY.

  sql/ha_federated.h@stripped, 2007-06-19 19:36:43-07:00, antony@stripped +2 -0
    bug25511
      we need to store remote key which failed and if 
      ON DUPLICATE KEY UPDATE is in effect - it is indicated by
      HA_EXTRA_RETRIEVE_PRIMARY_KEY

# 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:	antony
# Host:	ppcg5.local
# Root:	/private/Network/Servers/anubis.xiphis.org/home/antony/work/p2-bug25511.1

--- 1.41/mysql-test/r/federated.result	2007-06-19 16:58:23 -07:00
+++ 1.42/mysql-test/r/federated.result	2007-06-19 19:36:42 -07:00
@@ -1867,6 +1867,17 @@
 3	Curly
 drop table federated.t1;
 drop table federated.t1;
+create table federated.t1 (a int primary key, b int, c varchar(64));
+insert into federated.t1 values (1,2,"original");
+create table federated.t1 (a int primary key, b int, c varchar(64))
+ENGINE=FEDERATED
+connection='mysql://root@stripped:12002/federated/t1';
+insert into federated.t1 values(1,3,"new") on duplicate key update b=b+100;
+select * from federated.t1;
+a	b	c
+1	102	original
+drop table federated.t1;
+drop table federated.t1;
 DROP TABLE IF EXISTS federated.t1;
 DROP DATABASE IF EXISTS federated;
 DROP TABLE IF EXISTS federated.t1;

--- 1.36/mysql-test/t/federated.test	2007-06-19 16:58:23 -07:00
+++ 1.37/mysql-test/t/federated.test	2007-06-19 19:36:43 -07:00
@@ -1602,4 +1602,24 @@
 connection slave;
 drop table federated.t1;
 
+
+#
+# Bug#25511 Federated INSERT failures
+#
+connection slave;
+create table federated.t1 (a int primary key, b int, c varchar(64));
+insert into federated.t1 values (1,2,"original");
+connection master;
+eval create table federated.t1 (a int primary key, b int, c varchar(64))
+  ENGINE=FEDERATED
+  connection='mysql://root@stripped:$SLAVE_MYPORT/federated/t1';
+
+insert into federated.t1 values(1,3,"new") on duplicate key update b=b+100;
+select * from federated.t1;
+
+drop table federated.t1;
+connection slave;
+drop table federated.t1;
+
+
 source include/federated_cleanup.inc;

--- 1.76/sql/ha_federated.cc	2007-06-19 16:58:24 -07:00
+++ 1.77/sql/ha_federated.cc	2007-06-19 19:36:43 -07:00
@@ -1611,9 +1611,9 @@
   /*
     start both our field and field values strings
   */
-  if (replace_duplicates)
+  if (replace_duplicates && !retrieve_primary_key)
     insert_string.append(STRING_WITH_LEN("REPLACE INTO "));
-  else if (ignore_duplicates)
+  else if (ignore_duplicates && !retrieve_primary_key)
     insert_string.append(STRING_WITH_LEN("INSERT IGNORE INTO "));
   else
     insert_string.append(STRING_WITH_LEN("INSERT INTO "));
@@ -1819,7 +1819,7 @@
   update_string.length(0);
   where_string.length(0);
 
-  if (ignore_duplicates)
+  if (ignore_duplicates && !retrieve_primary_key)
     update_string.append(STRING_WITH_LEN("UPDATE IGNORE "));
   else
     update_string.append(STRING_WITH_LEN("UPDATE "));
@@ -2427,7 +2427,6 @@
 {
   char error_buffer[FEDERATED_QUERY_BUFFER_SIZE];
   char status_buf[FEDERATED_QUERY_BUFFER_SIZE];
-  char escaped_table_name[FEDERATED_QUERY_BUFFER_SIZE];
   int error;
   uint error_code;
   MYSQL_RES *result= 0;
@@ -2441,14 +2440,7 @@
   {
     status_query_string.length(0);
     status_query_string.append(FEDERATED_INFO);
-    status_query_string.append(FEDERATED_SQUOTE);
-
-    escape_string_for_mysql(&my_charset_bin, (char *)escaped_table_name,
-                            sizeof(escaped_table_name),
-                            share->table_name,
-                            share->table_name_length);
-    status_query_string.append(escaped_table_name);
-    status_query_string.append(FEDERATED_SQUOTE);
+    append_ident(&status_query_string, share->table_name, share->table_name_length, '\'');
 
     if (mysql_real_query(mysql, status_query_string.ptr(),
                          status_query_string.length()))
@@ -2498,6 +2490,89 @@
     block_size= 4096;
   }
 
+  if (flag & HA_STATUS_ERRKEY && remote_errkey != MAX_KEY)
+  {
+    uint key;
+    key_map keys_to_check= table->s->keys_in_use;
+  
+    mysql_free_result(result);
+    result= 0;
+    
+    /*
+      we have to ask the remote server to describe the key and we then
+      have to match it against a key definition we know of locally
+    */
+    status_query_string.length(0);
+    status_query_string.append(STRING_WITH_LEN("SHOW KEYS FROM "));
+    append_ident(&status_query_string, share->table_name, share->table_name_length);
+    
+    if (mysql_real_query(mysql, status_query_string.ptr(),
+                         status_query_string.length()))
+      goto error;
+    if (!(result= mysql_store_result(mysql)))
+      goto error;
+    
+
+    for (row= mysql_fetch_row(result), key= 1; key <= remote_errkey; key++)
+    {
+      int error= 0;
+      char *tmp;
+      uint key_part= (uint) my_strtoll10(row[3], &tmp, &error);
+
+      /* eat out of order rows for safety */
+      while (key_part != 1 && (row= mysql_fetch_row(result)))
+        key_part= (uint) my_strtoll10(row[3], &tmp, &error);
+
+      if (!row || error)
+        break;
+        
+      DBUG_ASSERT(key_part == 1);
+      
+      for (;;)
+      {
+        uint next_part, i;
+        if (key == remote_errkey)
+        {
+          for (i= 0; i < table->s->keys; i++)
+          {
+            KEY_PART_INFO *part= table->key_info[i].key_part + (key_part - 1);
+            if (!keys_to_check.is_set(i))
+              continue;
+            if (table->key_info[i].key_parts >= key_part &&
+                !strcasecmp(row[4], part->field->field_name))
+              continue;
+            keys_to_check.clear_bit(i);
+          } 
+        }
+      
+        if (!(row= mysql_fetch_row(result)) ||
+            (next_part= (uint) my_strtoll10(row[3], &tmp, &error)) <= key_part ||
+            error)
+        {
+          if (key == remote_errkey)
+          {
+            /* unset keys which have more key columns than desired */
+            for (i= 0; i < table->s->keys; i++)
+              if (table->key_info[i].key_parts > key_part)
+                keys_to_check.clear_bit(i);
+          }
+          
+          break;
+        }
+        key_part= next_part;
+      }
+    }
+
+    /* scan for the first matching key */    
+    for (key= 0; key < table->s->keys; key++)
+    {
+      if (!keys_to_check.is_set(key))
+        continue;
+      table->file->errkey= key;
+      break;
+    }
+  }
+
   if (result)
     mysql_free_result(result);
 
@@ -2534,9 +2609,13 @@
   case HA_EXTRA_WRITE_CANNOT_REPLACE:
     replace_duplicates= FALSE;
     break;
+  case HA_EXTRA_RETRIEVE_PRIMARY_KEY:
+    retrieve_primary_key= TRUE;
+    break;
   case HA_EXTRA_RESET:
     ignore_duplicates= FALSE;
     replace_duplicates= FALSE;
+    retrieve_primary_key= FALSE;
     break;
   default:
     /* do nothing */
@@ -2676,6 +2755,42 @@
   DBUG_ENTER("ha_federated::stash_remote_error()");
   remote_error_number= mysql_errno(mysql);
   strmake(remote_error_buf, mysql_error(mysql), sizeof(remote_error_buf)-1);
+  switch ((remote_error_number= mysql_errno(mysql)))
+  {
+  case ER_DUP_ENTRY:
+  {
+    const char *pos= remote_error_buf + strlen(remote_error_buf) - 1, *idx;
+    remote_errkey= MAX_KEY;
+
+    /* for this error message, the key is the last integer in the string */
+    for (idx= 0; pos >= remote_error_buf; pos--)
+    {
+      if (*pos < '0' || *pos > '9')
+      {
+        if (idx)
+          break;
+        continue;
+      }
+      idx= pos;
+    }
+    
+    /*
+      if we have found an integer, parse it and store in remote_errkey
+    */
+    if (idx)
+    {
+      char *tmp;
+      int error= 0;
+      uint key= (uint) my_strtoll10(idx, &tmp, &error);
+      if (!error)
+        remote_errkey= key;
+    }
+    
+    DBUG_RETURN(HA_ERR_FOUND_DUPP_KEY);
+  }
+  default:
+    break;
+  }
   DBUG_RETURN(HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM);
 }
 

--- 1.31/sql/ha_federated.h	2007-06-19 16:58:24 -07:00
+++ 1.32/sql/ha_federated.h	2007-06-19 19:36:43 -07:00
@@ -151,8 +151,10 @@
   MYSQL_RES *stored_result;
   uint fetch_num; // stores the fetch num
   MYSQL_ROW_OFFSET current_position;  // Current position used by ::position()
+  uint remote_errkey;
   int remote_error_number;
   char remote_error_buf[FEDERATED_QUERY_BUFFER_SIZE];
+  bool retrieve_primary_key;
   bool ignore_duplicates, replace_duplicates;
 
 private:
Thread
bk commit into 5.0 tree (antony:1.2493) BUG#25511antony20 Jun
  • Re: bk commit into 5.0 tree (antony:1.2493) BUG#25511Jim Winstead20 Jun
    • Re: bk commit into 5.0 tree (antony:1.2493) BUG#25511Antony T Curtis20 Jun