Commit 4b25d4a0 authored by unknown's avatar unknown

ndb_insert.test, ndb_insert.result, ha_ndbcluster.cc:

  Bug#27980 INSERT IGNORE wrongly ignores NULLs in unique index: added check for null values


mysql-test/t/ndb_insert.test:
  Bug#27980 INSERT IGNORE wrongly ignores NULLs in unique index: added check for null values
sql/ha_ndbcluster.cc:
  Bug#27980 INSERT IGNORE wrongly ignores NULLs in unique index: added check for null values
mysql-test/r/ndb_insert.result:
  Bug#27980 INSERT IGNORE wrongly ignores NULLs in unique index: added check for null values
parent a7718cf5
...@@ -649,3 +649,11 @@ pk a ...@@ -649,3 +649,11 @@ pk a
6 NULL 6 NULL
7 4 7 4
DROP TABLE t1; DROP TABLE t1;
create table t1(a int primary key, b int, unique key(b)) engine=ndb;
insert ignore into t1 values (1,0), (2,0), (2,null), (3,null);
select * from t1 order by a;
a b
1 0
2 NULL
3 NULL
drop table t1;
...@@ -630,4 +630,13 @@ INSERT IGNORE INTO t1 VALUES (4,NULL),(5,NULL),(6,NULL),(7,4); ...@@ -630,4 +630,13 @@ INSERT IGNORE INTO t1 VALUES (4,NULL),(5,NULL),(6,NULL),(7,4);
SELECT * FROM t1 ORDER BY pk; SELECT * FROM t1 ORDER BY pk;
DROP TABLE t1; DROP TABLE t1;
#
# Bug #27980 INSERT IGNORE wrongly ignores NULLs in unique index
#
create table t1(a int primary key, b int, unique key(b)) engine=ndb;
insert ignore into t1 values (1,0), (2,0), (2,null), (3,null);
select * from t1 order by a;
drop table t1;
# End of 4.1 tests # End of 4.1 tests
...@@ -1630,6 +1630,34 @@ bool ha_ndbcluster::check_all_operations_for_error(NdbTransaction *trans, ...@@ -1630,6 +1630,34 @@ bool ha_ndbcluster::check_all_operations_for_error(NdbTransaction *trans,
DBUG_RETURN(true); DBUG_RETURN(true);
} }
/**
* Check if record contains any null valued columns that are part of a key
*/
static
int
check_null_in_record(const KEY* key_info, const byte *record)
{
KEY_PART_INFO *curr_part, *end_part;
curr_part= key_info->key_part;
end_part= curr_part + key_info->key_parts;
while (curr_part != end_part)
{
if (curr_part->null_bit &&
(record[curr_part->null_offset] & curr_part->null_bit))
return 1;
curr_part++;
}
return 0;
/*
We could instead pre-compute a bitmask in table_share with one bit for
every null-bit in the key, and so check this just by OR'ing the bitmask
with the null bitmap in the record.
But not sure it's worth it.
*/
}
/* /*
* Peek to check if any rows already exist with conflicting * Peek to check if any rows already exist with conflicting
* primary key or unique index values * primary key or unique index values
...@@ -1671,7 +1699,17 @@ int ha_ndbcluster::peek_indexed_rows(const byte *record, bool check_pk) ...@@ -1671,7 +1699,17 @@ int ha_ndbcluster::peek_indexed_rows(const byte *record, bool check_pk)
if (i != table->s->primary_key && if (i != table->s->primary_key &&
key_info->flags & HA_NOSAME) key_info->flags & HA_NOSAME)
{ {
// A unique index is defined on table /*
A unique index is defined on table.
We cannot look up a NULL field value in a unique index. But since
keys with NULLs are not indexed, such rows cannot conflict anyway, so
we just skip the index in this case.
*/
if (check_null_in_record(key_info, record))
{
DBUG_PRINT("info", ("skipping check for key with NULL"));
continue;
}
NdbIndexOperation *iop; NdbIndexOperation *iop;
NDBINDEX *unique_index = (NDBINDEX *) m_index[i].unique_index; NDBINDEX *unique_index = (NDBINDEX *) m_index[i].unique_index;
key_part= key_info->key_part; key_part= key_info->key_part;
...@@ -2816,7 +2854,7 @@ int ha_ndbcluster::index_end() ...@@ -2816,7 +2854,7 @@ int ha_ndbcluster::index_end()
} }
/** /**
* Check if key contains null * Check if key contains nullable columns
*/ */
static static
int int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment