Fixed bug #25798.
This bug may manifest itself not only with the queries for which the index-merge access method is chosen. It also may display itself for queries with DISTINCT. The bug was in how the Unique::get method used the merge_buffers function. To compare elements in the the queue employed by merge_buffers() it must use the buffpek_compare function rather than the function for binary comparison. mysql-test/r/innodb_mysql.result: Added a test case for bug #25798. mysql-test/t/innodb_mysql.test: Added a test case for bug #25798. sql/filesort.cc: Fixed bug #25798. The function merge_buffers() when called from the Uniques::get method must use function buffpek_compare to compare elements in the queue it employs. The pointer to buffpek_compare and the info for the function that compares sorted records are passed to merge_buffers through certain designated fields of the SORTPARAM structure. sql/sql_sort.h: Fixed bug #25798. Added fields to the SORTPARAM structure to be used in the function merge_buffers when called by the Uniques::get method. sql/uniques.cc: Fixed bug 25798. The function merge_buffers() when called from the Uniques::get method must use function buffpek_compare to compare elements in the queue it employes.
This commit is contained in:
parent
8dcd5fca69
commit
07dcc80023
@ -676,4 +676,55 @@ INSERT INTO t1 VALUES (1);
|
||||
switch to connection default
|
||||
SET AUTOCOMMIT=default;
|
||||
DROP TABLE t1,t2;
|
||||
CREATE TABLE t1 (
|
||||
id int NOT NULL auto_increment PRIMARY KEY,
|
||||
b int NOT NULL,
|
||||
c datetime NOT NULL,
|
||||
INDEX idx_b(b),
|
||||
INDEX idx_c(c)
|
||||
) ENGINE=InnoDB;
|
||||
CREATE TABLE t2 (
|
||||
b int NOT NULL auto_increment PRIMARY KEY,
|
||||
c datetime NOT NULL
|
||||
) ENGINE= MyISAM;
|
||||
INSERT INTO t2(c) VALUES ('2007-01-01');
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t1(b,c) SELECT b,c FROM t2;
|
||||
UPDATE t2 SET c='2007-01-02';
|
||||
INSERT INTO t1(b,c) SELECT b,c FROM t2;
|
||||
UPDATE t2 SET c='2007-01-03';
|
||||
INSERT INTO t1(b,c) SELECT b,c FROM t2;
|
||||
set @@sort_buffer_size=8192;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
3072
|
||||
EXPLAIN
|
||||
SELECT COUNT(*) FROM t1
|
||||
WHERE (c >= '2007-01-02' AND c <= '2007-01-03') OR b >= 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL idx_b,idx_c NULL NULL NULL 3263 Using where
|
||||
SELECT COUNT(*) FROM t1
|
||||
WHERE (c >= '2007-01-02' AND c <= '2007-01-03') OR b >= 1;
|
||||
COUNT(*)
|
||||
3072
|
||||
EXPLAIN
|
||||
SELECT COUNT(*) FROM t1 FORCE INDEX(idx_b, idx_c)
|
||||
WHERE (c >= '2007-01-02' AND c <= '2007-01-03') OR b >= 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index_merge idx_b,idx_c idx_c,idx_b 8,4 NULL 3262 Using sort_union(idx_c,idx_b); Using where
|
||||
SELECT COUNT(*) FROM t1 FORCE INDEX(idx_b, idx_c)
|
||||
WHERE (c >= '2007-01-02' AND c <= '2007-01-03') OR b >= 1;
|
||||
COUNT(*)
|
||||
3072
|
||||
set @@sort_buffer_size=default;
|
||||
DROP TABLE t1,t2;
|
||||
End of 5.0 tests
|
||||
|
@ -670,5 +670,59 @@ DISCONNECT c1;
|
||||
DISCONNECT c2;
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
#
|
||||
# Bug #25798: a query with forced index merge returns wrong result
|
||||
#
|
||||
|
||||
CREATE TABLE t1 (
|
||||
id int NOT NULL auto_increment PRIMARY KEY,
|
||||
b int NOT NULL,
|
||||
c datetime NOT NULL,
|
||||
INDEX idx_b(b),
|
||||
INDEX idx_c(c)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE t2 (
|
||||
b int NOT NULL auto_increment PRIMARY KEY,
|
||||
c datetime NOT NULL
|
||||
) ENGINE= MyISAM;
|
||||
|
||||
INSERT INTO t2(c) VALUES ('2007-01-01');
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
INSERT INTO t2(c) SELECT c FROM t2;
|
||||
|
||||
INSERT INTO t1(b,c) SELECT b,c FROM t2;
|
||||
UPDATE t2 SET c='2007-01-02';
|
||||
INSERT INTO t1(b,c) SELECT b,c FROM t2;
|
||||
UPDATE t2 SET c='2007-01-03';
|
||||
INSERT INTO t1(b,c) SELECT b,c FROM t2;
|
||||
|
||||
set @@sort_buffer_size=8192;
|
||||
|
||||
SELECT COUNT(*) FROM t1;
|
||||
|
||||
EXPLAIN
|
||||
SELECT COUNT(*) FROM t1
|
||||
WHERE (c >= '2007-01-02' AND c <= '2007-01-03') OR b >= 1;
|
||||
SELECT COUNT(*) FROM t1
|
||||
WHERE (c >= '2007-01-02' AND c <= '2007-01-03') OR b >= 1;
|
||||
|
||||
EXPLAIN
|
||||
SELECT COUNT(*) FROM t1 FORCE INDEX(idx_b, idx_c)
|
||||
WHERE (c >= '2007-01-02' AND c <= '2007-01-03') OR b >= 1;
|
||||
SELECT COUNT(*) FROM t1 FORCE INDEX(idx_b, idx_c)
|
||||
WHERE (c >= '2007-01-02' AND c <= '2007-01-03') OR b >= 1;
|
||||
|
||||
set @@sort_buffer_size=default;
|
||||
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
--echo End of 5.0 tests
|
||||
|
@ -1052,6 +1052,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
|
||||
BUFFPEK *buffpek;
|
||||
QUEUE queue;
|
||||
qsort2_cmp cmp;
|
||||
void *first_cmp_arg;
|
||||
volatile THD::killed_state *killed= ¤t_thd->killed;
|
||||
THD::killed_state not_killable;
|
||||
DBUG_ENTER("merge_buffers");
|
||||
@ -1077,9 +1078,18 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
|
||||
/* The following will fire if there is not enough space in sort_buffer */
|
||||
DBUG_ASSERT(maxcount!=0);
|
||||
|
||||
if (param->unique_buff)
|
||||
{
|
||||
cmp= param->compare;
|
||||
first_cmp_arg= (void *) ¶m->cmp_context;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmp= get_ptr_compare(sort_length);
|
||||
first_cmp_arg= (void*) &sort_length;
|
||||
}
|
||||
if (init_queue(&queue, (uint) (Tb-Fb)+1, offsetof(BUFFPEK,key), 0,
|
||||
(queue_compare) (cmp= get_ptr_compare(sort_length)),
|
||||
(void*) &sort_length))
|
||||
(queue_compare) cmp, first_cmp_arg))
|
||||
DBUG_RETURN(1); /* purecov: inspected */
|
||||
for (buffpek= Fb ; buffpek <= Tb ; buffpek++)
|
||||
{
|
||||
@ -1132,7 +1142,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
|
||||
buffpek= (BUFFPEK*) queue_top(&queue);
|
||||
if (cmp) // Remove duplicates
|
||||
{
|
||||
if (!(*cmp)(&sort_length, &(param->unique_buff),
|
||||
if (!(*cmp)(first_cmp_arg, &(param->unique_buff),
|
||||
(uchar**) &buffpek->key))
|
||||
goto skip_duplicate;
|
||||
memcpy(param->unique_buff, (uchar*) buffpek->key, rec_length);
|
||||
@ -1184,7 +1194,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
|
||||
*/
|
||||
if (cmp)
|
||||
{
|
||||
if (!(*cmp)(&sort_length, &(param->unique_buff), (uchar**) &buffpek->key))
|
||||
if (!(*cmp)(first_cmp_arg, &(param->unique_buff), (uchar**) &buffpek->key))
|
||||
{
|
||||
buffpek->key+= rec_length; // Remove duplicate
|
||||
--buffpek->mem_count;
|
||||
|
@ -50,6 +50,12 @@ typedef struct st_buffpek { /* Struktur om sorteringsbuffrarna */
|
||||
ulong max_keys; /* Max keys in buffert */
|
||||
} BUFFPEK;
|
||||
|
||||
struct BUFFPEK_COMPARE_CONTEXT
|
||||
{
|
||||
qsort_cmp2 key_compare;
|
||||
void *key_compare_arg;
|
||||
};
|
||||
|
||||
typedef struct st_sort_param {
|
||||
uint rec_length; /* Length of sorted records */
|
||||
uint sort_length; /* Length of sorted columns */
|
||||
@ -65,6 +71,9 @@ typedef struct st_sort_param {
|
||||
uchar *unique_buff;
|
||||
bool not_killable;
|
||||
char* tmp_buffer;
|
||||
/* The fields below are used only by Unique class */
|
||||
qsort2_cmp compare;
|
||||
BUFFPEK_COMPARE_CONTEXT cmp_context;
|
||||
} SORTPARAM;
|
||||
|
||||
|
||||
|
@ -361,17 +361,12 @@ Unique::reset()
|
||||
}
|
||||
|
||||
/*
|
||||
The comparison function, passed to queue_init() in merge_walk() must
|
||||
The comparison function, passed to queue_init() in merge_walk() and in
|
||||
merge_buffers() when the latter is called from Uniques::get() must
|
||||
use comparison function of Uniques::tree, but compare members of struct
|
||||
BUFFPEK.
|
||||
*/
|
||||
|
||||
struct BUFFPEK_COMPARE_CONTEXT
|
||||
{
|
||||
qsort_cmp2 key_compare;
|
||||
void *key_compare_arg;
|
||||
};
|
||||
|
||||
C_MODE_START
|
||||
|
||||
static int buffpek_compare(void *arg, byte *key_ptr1, byte *key_ptr2)
|
||||
@ -630,6 +625,10 @@ bool Unique::get(TABLE *table)
|
||||
sort_param.unique_buff= sort_buffer+(sort_param.keys*
|
||||
sort_param.sort_length);
|
||||
|
||||
sort_param.compare= (qsort2_cmp) buffpek_compare;
|
||||
sort_param.cmp_context.key_compare= tree.compare;
|
||||
sort_param.cmp_context.key_compare_arg= tree.custom_arg;
|
||||
|
||||
/* Merge the buffers to one file, removing duplicates */
|
||||
if (merge_many_buff(&sort_param,sort_buffer,file_ptr,&maxbuffer,&file))
|
||||
goto err;
|
||||
|
Loading…
x
Reference in New Issue
Block a user