Bug #5312 Ndb Cluster returns wrong error code for duplicate key at insert
Submitted: 31 Aug 2004 11:08 Modified: 17 Nov 2004 15:04
Reporter: Martin Skold
Status: To be fixed later
Category:Server: Cluster Severity:S3 (Non-critical)
Version: OS:Any
Assigned to: Martin Skold Target Version:

[31 Aug 2004 11:08] Martin Skold
Description:
Ndb Cluster returns wrong error code for duplicate key at insert

How to repeat:
Trudy Pelzer wrote: 
I have three tables, called s (Type=MyISAM), s_i (Type=InnoDB),
and s_n (Type=NDBCluster). The tables all look like this (note
the primary key on column sno):

mysql> show columns from s_n;
+--------+--------------+------+-----+---------+-------+
| Field  | Type         | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| sno    | char(3)      |      | PRI |         |       |
| sname  | varchar(8)   | YES  |     | NULL    |       |
| status | decimal(3,0) | YES  |     | NULL    |       |
| city   | varchar(10)  | YES  |     | NULL    |       |
+--------+--------------+------+-----+---------+-------+
4 rows in set (0.01 sec)

I attempt to add duplicate key values to each table:

mysql> insert into s (sno) values('s6');
Query OK, 1 row affected (0.00 sec)
mysql> insert into s (sno) values('s6');
ERROR 1062 (23000): Duplicate entry 's6' for key 1

mysql> insert into s_i (sno) values('s6');
Query OK, 1 row affected (0.00 sec)
mysql> insert into s_i (sno) values('s6');
ERROR 1062 (23000): Duplicate entry 's6' for key 1

mysql> insert into s_n (sno) values('s6');
Query OK, 1 row affected (0.00 sec)
mysql> insert into s_n (sno) values('s6');
ERROR 1022 (23000): Can't write; duplicate key in table 's_n'

Note that the MyISAM and InnoDB table attempts return
ERROR 1062 (23000): Duplicate entry 's6' for key 1.
But the Cluster table attempt returns
ERROR 1022 (23000): Can't write; duplicate key in table 's_n'

I consider this a bug. If a programmer, writing an error handling
routine, is depending on a specific error being returned by MySQL,
it should be the same error regardless of which engine is in use. 

Suggested fix:
Handler must set errkey before returning error at write_row:
In handler.cc
/* Return key if error because of duplicated keys */

uint handler::get_dup_key(int error)
{
  DBUG_ENTER("handler::get_dup_key");
  table->file->errkey  = (uint) -1;
  if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOUND_DUPP_UNIQUE)
    info(HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK);
  DBUG_RETURN(table->file->errkey);
}

  case HA_ERR_FOUND_DUPP_KEY:
  {
    uint key_nr=get_dup_key(error);
    if ((int) key_nr >= 0)
    {
      /* Write the dupplicated key in the error message */
      char key[MAX_KEY_LENGTH];
      String str(key,sizeof(key),system_charset_info);
      key_unpack(&str,table,(uint) key_nr);
      uint max_length=MYSQL_ERRMSG_SIZE-(uint) strlen(ER(ER_DUP_ENTRY)); // 1062
      if (str.length() >= max_length)
      {
        str.length(max_length-4);
        str.append("...");
      }
      my_error(ER_DUP_ENTRY,MYF(0),str.c_ptr(),key_nr+1);
      DBUG_VOID_RETURN;
    }
    textno=ER_DUP_KEY; // 1022
    break;
  }
[31 Aug 2004 17:01] Martin Skold
Pushed to mysql-4.1
[17 Nov 2004 15:04] Martin Skold
We are backing out of this fix since this error code requires that the
handler returns the key value that caused the error. This would be
very expensive to do in a handler that can batch many inserts at once,
all primary keys would then have to be saved for each batch wasting
a lot of space. Error code 1022 is also a valid MySQL code and users
should be prepared to get that one as well. An alternative would be to
have some way of disable the key value part of error 1062 output (but
then 1062 and 1022 would be identical).
[17 Nov 2004 16:52] Martin Skold
Does not seem to be possible to use error code 1022 since
then INSERT ... ON DUPLICATE KEY ... will not work!
Oh well, innodb has the same bug, see we use 1062 anyhow then.
[14 May 2006 23:32] Hartmut Holzgraefe
This seems to work as expected now in latest 4.1 and 5.0 now so that we can close this
bug?