Commit c33c92d0 authored by unknown's avatar unknown

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.


include/queues.h:
  Bug #31890 Partitions: ORDER BY DESC in InnoDB not working
  
  max_at_top policy changed
mysql-test/r/partition.result:
  Bug #31890 Partitions: ORDER BY DESC in InnoDB not working
  
  test result
mysql-test/t/partition.test:
  Bug #31890 Partitions: ORDER BY DESC in InnoDB not working
  
  test case
mysys/queues.c:
  Bug #31890 Partitions: ORDER BY DESC in InnoDB not working.
  
  queue->max_at_top policy changed - now it can either be '1' or '-1'.
  We multiply comparison result on max_at_top to get the proper
  direction.
parent d68b313d
......@@ -31,8 +31,8 @@ typedef struct st_queue {
void *first_cmp_arg;
uint elements;
uint max_elements;
uint offset_to_key; /* compare is done on element+offset */
int max_at_top; /* Set if queue_top gives max */
uint offset_to_key; /* compare is done on element+offset */
int max_at_top; /* Normally 1, set to -1 if queue_top gives max */
int (*compare)(void *, uchar *,uchar *);
uint auto_extent;
} QUEUE;
......@@ -43,7 +43,7 @@ typedef struct st_queue {
#define queue_replaced(queue) _downheap(queue,1)
#define queue_set_cmp_arg(queue, set_arg) (queue)->first_cmp_arg= 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 *);
int init_queue(QUEUE *queue,uint max_elements,uint offset_to_key,
......
......@@ -1296,4 +1296,39 @@ create table t1
partition by key(s1) partitions 3;
insert into t1 values (null,null);
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
......@@ -1549,4 +1549,31 @@ while ($cnt)
--enable_query_log
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
......@@ -61,7 +61,7 @@ int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
queue->first_cmp_arg=first_cmp_arg;
queue->max_elements=max_elements;
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);
}
......@@ -137,7 +137,7 @@ int reinit_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
queue->compare=compare;
queue->first_cmp_arg=first_cmp_arg;
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);
DBUG_RETURN(0);
}
......@@ -208,16 +208,14 @@ void delete_queue(QUEUE *queue)
void queue_insert(register QUEUE *queue, uchar *element)
{
reg2 uint idx, next;
int cmp;
DBUG_ASSERT(queue->elements < queue->max_elements);
queue->root[0]= element;
idx= ++queue->elements;
/* max_at_top swaps the comparison if we want to order by desc */
while ((cmp= queue->compare(queue->first_cmp_arg,
element + queue->offset_to_key,
queue->root[(next= idx >> 1)] +
queue->offset_to_key)) &&
(cmp ^ queue->max_at_top) < 0)
while ((queue->compare(queue->first_cmp_arg,
element + queue->offset_to_key,
queue->root[(next= idx >> 1)] +
queue->offset_to_key) * queue->max_at_top) < 0)
{
queue->root[idx]= queue->root[next];
idx= next;
......@@ -287,19 +285,17 @@ void _downheap(register QUEUE *queue, uint idx)
while (idx <= half_queue)
{
int cmp;
next_index=idx+idx;
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->root[next_index+1]+offset_to_key) *
queue->max_at_top) > 0)
next_index++;
if (first &&
(((cmp=queue->compare(queue->first_cmp_arg,
queue->root[next_index]+offset_to_key,
element+offset_to_key)) == 0) ||
((cmp ^ queue->max_at_top) > 0)))
(((queue->compare(queue->first_cmp_arg,
queue->root[next_index]+offset_to_key,
element+offset_to_key) * queue->max_at_top) >= 0)))
{
queue->root[idx]= element;
return;
......@@ -314,7 +310,7 @@ void _downheap(register QUEUE *queue, uint idx)
{
if ((queue->compare(queue->first_cmp_arg,
queue->root[next_index]+offset_to_key,
element+offset_to_key) ^
element+offset_to_key) *
queue->max_at_top) < 0)
break;
queue->root[idx]=queue->root[next_index];
......@@ -334,7 +330,6 @@ void _downheap(register QUEUE *queue, uint idx)
{
uchar *element;
uint elements,half_queue,next_index,offset_to_key;
int cmp;
offset_to_key=queue->offset_to_key;
element=queue->root[idx];
......@@ -346,13 +341,12 @@ void _downheap(register QUEUE *queue, uint idx)
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->root[next_index+1]+offset_to_key) *
queue->max_at_top) > 0)
next_index++;
if ((cmp=queue->compare(queue->first_cmp_arg,
queue->root[next_index]+offset_to_key,
element+offset_to_key)) == 0 ||
(cmp ^ queue->max_at_top) > 0)
if ((queue->compare(queue->first_cmp_arg,
queue->root[next_index]+offset_to_key,
element+offset_to_key) * queue->max_at_top) >= 0)
break;
queue->root[idx]=queue->root[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