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:
17
mysql-test/suite/innodb_plugin/r/innodb_bug53290.result
Normal file
17
mysql-test/suite/innodb_plugin/r/innodb_bug53290.result
Normal 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;
|
22
mysql-test/suite/innodb_plugin/t/innodb_bug53290.test
Normal file
22
mysql-test/suite/innodb_plugin/t/innodb_bug53290.test
Normal 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;
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Reference in New Issue
Block a user