summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@oracle.com>2010-05-05 15:39:01 +0300
committerMarko Mäkelä <marko.makela@oracle.com>2010-05-05 15:39:01 +0300
commit326d75bd414290c1548b5ca337c19887c7165d76 (patch)
tree6f2d48994b50feb7c4b60f9613f980d811b6a94b
parentfa2c00d316371620d98073737989b68c2c034ce8 (diff)
downloadmariadb-git-326d75bd414290c1548b5ca337c19887c7165d76.tar.gz
Merge a contribution from Ryan Mack at Facebook:
Bugfix for 53290, fast unique index creation fails on duplicate null values Summary: Bug in the fast index creation code incorrectly considers null values to be duplicates during block merging. Innodb policy is that multiple null values are allowed in a unique index. Null duplicates were correctly ignored while sorting individual blocks and with slow index creation. Test Plan: mtr, including new test, load dbs using deferred index creation DiffCamp Revision: 110840 Reviewed By: mcallaghan CC: mcallaghan, mysql-devel@lists Revert Plan: OK
-rw-r--r--mysql-test/suite/innodb_plugin/r/innodb_bug53290.result17
-rw-r--r--mysql-test/suite/innodb_plugin/t/innodb_bug53290.test22
-rw-r--r--storage/innodb_plugin/include/rem0cmp.h4
-rw-r--r--storage/innodb_plugin/rem/rem0cmp.c7
-rw-r--r--storage/innodb_plugin/row/row0merge.c13
5 files changed, 57 insertions, 6 deletions
diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug53290.result b/mysql-test/suite/innodb_plugin/r/innodb_bug53290.result
new file mode 100644
index 00000000000..46cd7248c4e
--- /dev/null
+++ b/mysql-test/suite/innodb_plugin/r/innodb_bug53290.result
@@ -0,0 +1,17 @@
+create table bug53290 (x bigint) engine=innodb;
+insert into bug53290 () values (),(),(),(),(),(),(),(),(),(),(),();
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+alter table bug53290 add unique index `idx` (x);
+drop table bug53290;
diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug53290.test b/mysql-test/suite/innodb_plugin/t/innodb_bug53290.test
new file mode 100644
index 00000000000..3f6b9b513f7
--- /dev/null
+++ b/mysql-test/suite/innodb_plugin/t/innodb_bug53290.test
@@ -0,0 +1,22 @@
+-- source include/have_innodb_plugin.inc
+
+create table bug53290 (x bigint) engine=innodb;
+
+insert into bug53290 () values (),(),(),(),(),(),(),(),(),(),(),();
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+insert into bug53290 select * from bug53290;
+
+alter table bug53290 add unique index `idx` (x);
+
+drop table bug53290;
diff --git a/storage/innodb_plugin/include/rem0cmp.h b/storage/innodb_plugin/include/rem0cmp.h
index 072f74267ea..2f751a38864 100644
--- a/storage/innodb_plugin/include/rem0cmp.h
+++ b/storage/innodb_plugin/include/rem0cmp.h
@@ -148,7 +148,9 @@ cmp_rec_rec_simple(
const rec_t* rec2, /*!< in: physical record */
const ulint* offsets1,/*!< in: rec_get_offsets(rec1, ...) */
const ulint* offsets2,/*!< in: rec_get_offsets(rec2, ...) */
- const dict_index_t* index); /*!< in: data dictionary index */
+ const dict_index_t* index, /*!< in: data dictionary index */
+ ibool* null_eq);/*!< out: set to TRUE if
+ found matching null values */
/*************************************************************//**
This function is used to compare two physical records. Only the common
first fields are compared, and if an externally stored field is
diff --git a/storage/innodb_plugin/rem/rem0cmp.c b/storage/innodb_plugin/rem/rem0cmp.c
index e6dab0bc66b..35b67992558 100644
--- a/storage/innodb_plugin/rem/rem0cmp.c
+++ b/storage/innodb_plugin/rem/rem0cmp.c
@@ -706,7 +706,9 @@ cmp_rec_rec_simple(
const rec_t* rec2, /*!< in: physical record */
const ulint* offsets1,/*!< in: rec_get_offsets(rec1, ...) */
const ulint* offsets2,/*!< in: rec_get_offsets(rec2, ...) */
- const dict_index_t* index) /*!< in: data dictionary index */
+ const dict_index_t* index, /*!< in: data dictionary index */
+ ibool* null_eq)/*!< out: set to TRUE if
+ found matching null values */
{
ulint rec1_f_len; /*!< length of current field in rec1 */
const byte* rec1_b_ptr; /*!< pointer to the current byte
@@ -753,6 +755,9 @@ cmp_rec_rec_simple(
|| rec2_f_len == UNIV_SQL_NULL) {
if (rec1_f_len == rec2_f_len) {
+ if (null_eq) {
+ *null_eq = TRUE;
+ }
goto next_field;
diff --git a/storage/innodb_plugin/row/row0merge.c b/storage/innodb_plugin/row/row0merge.c
index bedad2d1c71..832d29df710 100644
--- a/storage/innodb_plugin/row/row0merge.c
+++ b/storage/innodb_plugin/row/row0merge.c
@@ -1075,11 +1075,14 @@ row_merge_cmp(
record to be compared */
const ulint* offsets1, /*!< in: first record offsets */
const ulint* offsets2, /*!< in: second record offsets */
- const dict_index_t* index) /*!< in: index */
+ const dict_index_t* index, /*!< in: index */
+ ibool* null_eq) /*!< out: set to TRUE if
+ found matching null values */
{
int cmp;
- cmp = cmp_rec_rec_simple(mrec1, mrec2, offsets1, offsets2, index);
+ cmp = cmp_rec_rec_simple(mrec1, mrec2, offsets1, offsets2, index,
+ null_eq);
#ifdef UNIV_DEBUG
if (row_merge_print_cmp) {
@@ -1445,11 +1448,13 @@ corrupt:
}
while (mrec0 && mrec1) {
+ ibool null_eq = FALSE;
switch (row_merge_cmp(mrec0, mrec1,
- offsets0, offsets1, index)) {
+ offsets0, offsets1, index,
+ &null_eq)) {
case 0:
if (UNIV_UNLIKELY
- (dict_index_is_unique(index))) {
+ (dict_index_is_unique(index) && !null_eq)) {
innobase_rec_to_mysql(table, mrec0,
index, offsets0);
mem_heap_free(heap);