1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

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
This commit is contained in:
Marko Mäkelä
2010-05-05 15:39:01 +03:00
parent 2582a3e97b
commit 543ae0093c
5 changed files with 57 additions and 6 deletions

View File

@ -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;

View File

@ -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;

View File

@ -148,7 +148,9 @@ cmp_rec_rec_simple(
const rec_t* rec2, /*!< in: physical record */ const rec_t* rec2, /*!< in: physical record */
const ulint* offsets1,/*!< in: rec_get_offsets(rec1, ...) */ const ulint* offsets1,/*!< in: rec_get_offsets(rec1, ...) */
const ulint* offsets2,/*!< in: rec_get_offsets(rec2, ...) */ 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 This function is used to compare two physical records. Only the common
first fields are compared, and if an externally stored field is first fields are compared, and if an externally stored field is

View File

@ -706,7 +706,9 @@ cmp_rec_rec_simple(
const rec_t* rec2, /*!< in: physical record */ const rec_t* rec2, /*!< in: physical record */
const ulint* offsets1,/*!< in: rec_get_offsets(rec1, ...) */ const ulint* offsets1,/*!< in: rec_get_offsets(rec1, ...) */
const ulint* offsets2,/*!< in: rec_get_offsets(rec2, ...) */ 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 */ ulint rec1_f_len; /*!< length of current field in rec1 */
const byte* rec1_b_ptr; /*!< pointer to the current byte const byte* rec1_b_ptr; /*!< pointer to the current byte
@ -753,6 +755,9 @@ cmp_rec_rec_simple(
|| rec2_f_len == UNIV_SQL_NULL) { || rec2_f_len == UNIV_SQL_NULL) {
if (rec1_f_len == rec2_f_len) { if (rec1_f_len == rec2_f_len) {
if (null_eq) {
*null_eq = TRUE;
}
goto next_field; goto next_field;

View File

@ -1075,11 +1075,14 @@ row_merge_cmp(
record to be compared */ record to be compared */
const ulint* offsets1, /*!< in: first record offsets */ const ulint* offsets1, /*!< in: first record offsets */
const ulint* offsets2, /*!< in: second 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; 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 #ifdef UNIV_DEBUG
if (row_merge_print_cmp) { if (row_merge_print_cmp) {
@ -1445,11 +1448,13 @@ corrupt:
} }
while (mrec0 && mrec1) { while (mrec0 && mrec1) {
ibool null_eq = FALSE;
switch (row_merge_cmp(mrec0, mrec1, switch (row_merge_cmp(mrec0, mrec1,
offsets0, offsets1, index)) { offsets0, offsets1, index,
&null_eq)) {
case 0: case 0:
if (UNIV_UNLIKELY if (UNIV_UNLIKELY
(dict_index_is_unique(index))) { (dict_index_is_unique(index) && !null_eq)) {
innobase_rec_to_mysql(table, mrec0, innobase_rec_to_mysql(table, mrec0,
index, offsets0); index, offsets0);
mem_heap_free(heap); mem_heap_free(heap);