diff options
-rw-r--r-- | mysql-test/r/ndb_insert.result | 8 | ||||
-rw-r--r-- | mysql-test/t/ndb_insert.test | 9 | ||||
-rw-r--r-- | ndb/src/kernel/error/TimeModule.cpp | 2 | ||||
-rw-r--r-- | sql/ha_ndbcluster.cc | 42 |
4 files changed, 58 insertions, 3 deletions
diff --git a/mysql-test/r/ndb_insert.result b/mysql-test/r/ndb_insert.result index 0818f9ce9ac..e7275bde2b8 100644 --- a/mysql-test/r/ndb_insert.result +++ b/mysql-test/r/ndb_insert.result @@ -649,3 +649,11 @@ pk a 6 NULL 7 4 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; diff --git a/mysql-test/t/ndb_insert.test b/mysql-test/t/ndb_insert.test index bf25ca9a133..f346b7dc4ab 100644 --- a/mysql-test/t/ndb_insert.test +++ b/mysql-test/t/ndb_insert.test @@ -630,4 +630,13 @@ INSERT IGNORE INTO t1 VALUES (4,NULL),(5,NULL),(6,NULL),(7,4); SELECT * FROM t1 ORDER BY pk; 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 diff --git a/ndb/src/kernel/error/TimeModule.cpp b/ndb/src/kernel/error/TimeModule.cpp index 1c01f91f86b..2be734842ba 100644 --- a/ndb/src/kernel/error/TimeModule.cpp +++ b/ndb/src/kernel/error/TimeModule.cpp @@ -18,7 +18,7 @@ #include <ndb_global.h> #include "TimeModule.hpp" -static const char* cMonth[] = { "x", "January", "February", "Mars", "April", "May", "June", +static const char* cMonth[] = { "x", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; static const char* cDay[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 8701a216b8e..9b48e0d4f38 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -1630,6 +1630,34 @@ bool ha_ndbcluster::check_all_operations_for_error(NdbTransaction *trans, 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 * primary key or unique index values @@ -1671,7 +1699,17 @@ int ha_ndbcluster::peek_indexed_rows(const byte *record, bool check_pk) if (i != table->s->primary_key && 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; NDBINDEX *unique_index = (NDBINDEX *) m_index[i].unique_index; key_part= key_info->key_part; @@ -2816,7 +2854,7 @@ int ha_ndbcluster::index_end() } /** - * Check if key contains null + * Check if key contains nullable columns */ static int |