Bug #31890 Partitions: ORDER BY DESC in InnoDB not working.

It's not InnoDB specific bug.
Error is in QUEUE code, about the way we handle queue->max_at_top.
It's either '0' or '-2' and we do '^' operation to get the proper
direction. Though queue->compare() function can return '-2' as
a result of comparison sometimes. So we'll get
queue->compare() ^ queue->max_at_top == 0 (when max_at_top is -2)
and _downheap() function code will go wrong way here:
...
    if (next_index < elements &&
        (queue->compare(queue->first_cmp_arg,
                        queue->root[next_index]+offset_to_key,
                        queue->root[next_index+1]+offset_to_key) ^
         queue->max_at_top) > 0)
      next_index++;
...

Fixed by changing max_at_top to be either 1 or -1, doing
'* max_at_top' to get proper direction.
parent 19c3bd89
...@@ -31,8 +31,8 @@ typedef struct st_queue { ...@@ -31,8 +31,8 @@ typedef struct st_queue {
void *first_cmp_arg; void *first_cmp_arg;
uint elements; uint elements;
uint max_elements; uint max_elements;
uint offset_to_key; /* compare is done on element+offset */ uint offset_to_key; /* compare is done on element+offset */
int max_at_top; /* Set if queue_top gives max */ int max_at_top; /* Normally 1, set to -1 if queue_top gives max */
int (*compare)(void *, uchar *,uchar *); int (*compare)(void *, uchar *,uchar *);
uint auto_extent; uint auto_extent;
} QUEUE; } QUEUE;
...@@ -43,7 +43,7 @@ typedef struct st_queue { ...@@ -43,7 +43,7 @@ typedef struct st_queue {
#define queue_replaced(queue) _downheap(queue,1) #define queue_replaced(queue) _downheap(queue,1)
#define queue_set_cmp_arg(queue, set_arg) (queue)->first_cmp_arg= set_arg #define queue_set_cmp_arg(queue, set_arg) (queue)->first_cmp_arg= set_arg
#define queue_set_max_at_top(queue, set_arg) \ #define queue_set_max_at_top(queue, set_arg) \
(queue)->max_at_top= set_arg ? (-1 ^ 1) : 0 (queue)->max_at_top= set_arg ? -1 : 1
typedef int (*queue_compare)(void *,uchar *, uchar *); typedef int (*queue_compare)(void *,uchar *, uchar *);
int init_queue(QUEUE *queue,uint max_elements,uint offset_to_key, int init_queue(QUEUE *queue,uint max_elements,uint offset_to_key,
......
...@@ -1296,4 +1296,39 @@ create table t1 ...@@ -1296,4 +1296,39 @@ create table t1
partition by key(s1) partitions 3; partition by key(s1) partitions 3;
insert into t1 values (null,null); insert into t1 values (null,null);
drop table t1; drop table t1;
CREATE TABLE t1
(int_column INT, char_column CHAR(5),
PRIMARY KEY(char_column,int_column))
PARTITION BY KEY(char_column,int_column)
PARTITIONS 101;
INSERT INTO t1 (int_column, char_column) VALUES
( 39868 ,'zZZRW'),
( 545592 ,'zZzSD'),
( 4936 ,'zzzsT'),
( 9274 ,'ZzZSX'),
( 970185 ,'ZZzTN'),
( 786036 ,'zZzTO'),
( 37240 ,'zZzTv'),
( 313801 ,'zzzUM'),
( 782427 ,'ZZZva'),
( 907955 ,'zZZvP'),
( 453491 ,'zzZWV'),
( 756594 ,'ZZZXU'),
( 718061 ,'ZZzZH');
SELECT * FROM t1 ORDER BY char_column DESC;
int_column char_column
718061 ZZzZH
756594 ZZZXU
453491 zzZWV
907955 zZZvP
782427 ZZZva
313801 zzzUM
37240 zZzTv
786036 zZzTO
970185 ZZzTN
9274 ZzZSX
4936 zzzsT
545592 zZzSD
39868 zZZRW
DROP TABLE t1;
End of 5.1 tests End of 5.1 tests
...@@ -1549,4 +1549,31 @@ while ($cnt) ...@@ -1549,4 +1549,31 @@ while ($cnt)
--enable_query_log --enable_query_log
drop table t1; drop table t1;
#
# Bug #31890 Partitions: ORDER BY DESC in InnoDB not working
#
CREATE TABLE t1
(int_column INT, char_column CHAR(5),
PRIMARY KEY(char_column,int_column))
PARTITION BY KEY(char_column,int_column)
PARTITIONS 101;
INSERT INTO t1 (int_column, char_column) VALUES
( 39868 ,'zZZRW'),
( 545592 ,'zZzSD'),
( 4936 ,'zzzsT'),
( 9274 ,'ZzZSX'),
( 970185 ,'ZZzTN'),
( 786036 ,'zZzTO'),
( 37240 ,'zZzTv'),
( 313801 ,'zzzUM'),
( 782427 ,'ZZZva'),
( 907955 ,'zZZvP'),
( 453491 ,'zzZWV'),
( 756594 ,'ZZZXU'),
( 718061 ,'ZZzZH');
SELECT * FROM t1 ORDER BY char_column DESC;
DROP TABLE t1;
--echo End of 5.1 tests --echo End of 5.1 tests
...@@ -61,7 +61,7 @@ int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key, ...@@ -61,7 +61,7 @@ int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
queue->first_cmp_arg=first_cmp_arg; queue->first_cmp_arg=first_cmp_arg;
queue->max_elements=max_elements; queue->max_elements=max_elements;
queue->offset_to_key=offset_to_key; queue->offset_to_key=offset_to_key;
queue->max_at_top= max_at_top ? (-1 ^ 1) : 0; queue_set_max_at_top(queue, max_at_top);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -137,7 +137,7 @@ int reinit_queue(QUEUE *queue, uint max_elements, uint offset_to_key, ...@@ -137,7 +137,7 @@ int reinit_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
queue->compare=compare; queue->compare=compare;
queue->first_cmp_arg=first_cmp_arg; queue->first_cmp_arg=first_cmp_arg;
queue->offset_to_key=offset_to_key; queue->offset_to_key=offset_to_key;
queue->max_at_top= max_at_top ? (-1 ^ 1) : 0; queue_set_max_at_top(queue, max_at_top);
resize_queue(queue, max_elements); resize_queue(queue, max_elements);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -208,16 +208,14 @@ void delete_queue(QUEUE *queue) ...@@ -208,16 +208,14 @@ void delete_queue(QUEUE *queue)
void queue_insert(register QUEUE *queue, uchar *element) void queue_insert(register QUEUE *queue, uchar *element)
{ {
reg2 uint idx, next; reg2 uint idx, next;
int cmp;
DBUG_ASSERT(queue->elements < queue->max_elements); DBUG_ASSERT(queue->elements < queue->max_elements);
queue->root[0]= element; queue->root[0]= element;
idx= ++queue->elements; idx= ++queue->elements;
/* max_at_top swaps the comparison if we want to order by desc */ /* max_at_top swaps the comparison if we want to order by desc */
while ((cmp= queue->compare(queue->first_cmp_arg, while ((queue->compare(queue->first_cmp_arg,
element + queue->offset_to_key, element + queue->offset_to_key,
queue->root[(next= idx >> 1)] + queue->root[(next= idx >> 1)] +
queue->offset_to_key)) && queue->offset_to_key) * queue->max_at_top) < 0)
(cmp ^ queue->max_at_top) < 0)
{ {
queue->root[idx]= queue->root[next]; queue->root[idx]= queue->root[next];
idx= next; idx= next;
...@@ -287,19 +285,17 @@ void _downheap(register QUEUE *queue, uint idx) ...@@ -287,19 +285,17 @@ void _downheap(register QUEUE *queue, uint idx)
while (idx <= half_queue) while (idx <= half_queue)
{ {
int cmp;
next_index=idx+idx; next_index=idx+idx;
if (next_index < elements && if (next_index < elements &&
(queue->compare(queue->first_cmp_arg, (queue->compare(queue->first_cmp_arg,
queue->root[next_index]+offset_to_key, queue->root[next_index]+offset_to_key,
queue->root[next_index+1]+offset_to_key) ^ queue->root[next_index+1]+offset_to_key) *
queue->max_at_top) > 0) queue->max_at_top) > 0)
next_index++; next_index++;
if (first && if (first &&
(((cmp=queue->compare(queue->first_cmp_arg, (((queue->compare(queue->first_cmp_arg,
queue->root[next_index]+offset_to_key, queue->root[next_index]+offset_to_key,
element+offset_to_key)) == 0) || element+offset_to_key) * queue->max_at_top) >= 0)))
((cmp ^ queue->max_at_top) > 0)))
{ {
queue->root[idx]= element; queue->root[idx]= element;
return; return;
...@@ -314,7 +310,7 @@ void _downheap(register QUEUE *queue, uint idx) ...@@ -314,7 +310,7 @@ void _downheap(register QUEUE *queue, uint idx)
{ {
if ((queue->compare(queue->first_cmp_arg, if ((queue->compare(queue->first_cmp_arg,
queue->root[next_index]+offset_to_key, queue->root[next_index]+offset_to_key,
element+offset_to_key) ^ element+offset_to_key) *
queue->max_at_top) < 0) queue->max_at_top) < 0)
break; break;
queue->root[idx]=queue->root[next_index]; queue->root[idx]=queue->root[next_index];
...@@ -334,7 +330,6 @@ void _downheap(register QUEUE *queue, uint idx) ...@@ -334,7 +330,6 @@ void _downheap(register QUEUE *queue, uint idx)
{ {
uchar *element; uchar *element;
uint elements,half_queue,next_index,offset_to_key; uint elements,half_queue,next_index,offset_to_key;
int cmp;
offset_to_key=queue->offset_to_key; offset_to_key=queue->offset_to_key;
element=queue->root[idx]; element=queue->root[idx];
...@@ -346,13 +341,12 @@ void _downheap(register QUEUE *queue, uint idx) ...@@ -346,13 +341,12 @@ void _downheap(register QUEUE *queue, uint idx)
if (next_index < elements && if (next_index < elements &&
(queue->compare(queue->first_cmp_arg, (queue->compare(queue->first_cmp_arg,
queue->root[next_index]+offset_to_key, queue->root[next_index]+offset_to_key,
queue->root[next_index+1]+offset_to_key) ^ queue->root[next_index+1]+offset_to_key) *
queue->max_at_top) > 0) queue->max_at_top) > 0)
next_index++; next_index++;
if ((cmp=queue->compare(queue->first_cmp_arg, if ((queue->compare(queue->first_cmp_arg,
queue->root[next_index]+offset_to_key, queue->root[next_index]+offset_to_key,
element+offset_to_key)) == 0 || element+offset_to_key) * queue->max_at_top) >= 0)
(cmp ^ queue->max_at_top) > 0)
break; break;
queue->root[idx]=queue->root[next_index]; queue->root[idx]=queue->root[next_index];
idx=next_index; idx=next_index;
......
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