Commit 326d75bd authored by Marko Mäkelä's avatar Marko Mäkelä

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
parent fa2c00d3
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;
-- 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;
......@@ -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
......
......@@ -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;
......
......@@ -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);
......
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