Commit 7d915f01 authored by unknown's avatar unknown

BUG#21617 - crash when selecting from merge table with inconsistent indexes

Crash may happen when selecting from a merge table that has underlying
tables with less indexes than in a merge table itself.

If number of keys in merge table is not bigger than requested key number,
return error.


myisammrg/myrg_open.c:
  Store min(number of keys) in m_info instead of number of keys in last
  underlying table.
myisammrg/myrg_queue.c:
  Return error if inx passed to _myrg_init_queue function is not less
  than number of keys.
mysql-test/r/merge.result:
  A test case for bug#21617.
mysql-test/t/merge.test:
  A test case for bug#21617.
mysys/queues.c:
  Replaced annoying ifndef DBUG_OFF with DBUG_ASSERT, fixed coding style.
  The problem was that having queue overrun in debug build was hidden
  with this ifdef.
parent 186573b3
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
{ {
int save_errno,errpos=0; int save_errno,errpos=0;
uint files=0,i,dir_length,length,key_parts; uint files= 0, i, dir_length, length, key_parts, min_keys= 0;
ulonglong file_offset=0; ulonglong file_offset=0;
char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end; char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end;
MYRG_INFO *m_info=0; MYRG_INFO *m_info=0;
...@@ -106,6 +106,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) ...@@ -106,6 +106,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
files= 0; files= 0;
} }
m_info->reclength=isam->s->base.reclength; m_info->reclength=isam->s->base.reclength;
min_keys= isam->s->base.keys;
errpos=3; errpos=3;
} }
m_info->open_tables[files].table= isam; m_info->open_tables[files].table= isam;
...@@ -121,6 +122,8 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) ...@@ -121,6 +122,8 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
m_info->records+= isam->state->records; m_info->records+= isam->state->records;
m_info->del+= isam->state->del; m_info->del+= isam->state->del;
m_info->data_file_length+= isam->state->data_file_length; m_info->data_file_length+= isam->state->data_file_length;
if (min_keys > isam->s->base.keys)
min_keys= isam->s->base.keys;
for (i=0; i < key_parts; i++) for (i=0; i < key_parts; i++)
m_info->rec_per_key_part[i]+= (isam->s->state.rec_per_key_part[i] / m_info->rec_per_key_part[i]+= (isam->s->state.rec_per_key_part[i] /
m_info->tables); m_info->tables);
...@@ -138,7 +141,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) ...@@ -138,7 +141,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
my_errno=HA_ERR_RECORD_FILE_FULL; my_errno=HA_ERR_RECORD_FILE_FULL;
goto err; goto err;
} }
m_info->keys= files ? isam->s->base.keys : 0; m_info->keys= min_keys;
bzero((char*) &m_info->by_key,sizeof(m_info->by_key)); bzero((char*) &m_info->by_key,sizeof(m_info->by_key));
/* this works ok if the table list is empty */ /* this works ok if the table list is empty */
......
...@@ -51,6 +51,8 @@ int _myrg_init_queue(MYRG_INFO *info,int inx,enum ha_rkey_function search_flag) ...@@ -51,6 +51,8 @@ int _myrg_init_queue(MYRG_INFO *info,int inx,enum ha_rkey_function search_flag)
error=my_errno; error=my_errno;
} }
} }
else
my_errno= error= HA_ERR_WRONG_INDEX;
return error; return error;
} }
......
...@@ -766,3 +766,9 @@ Table Op Msg_type Msg_text ...@@ -766,3 +766,9 @@ Table Op Msg_type Msg_text
test.t1 check status OK test.t1 check status OK
test.t2 check status OK test.t2 check status OK
drop table t1, t2, t3; drop table t1, t2, t3;
CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES(2),(1);
CREATE TABLE t2(a INT, KEY(a)) ENGINE=MERGE UNION=(t1);
SELECT * FROM t2 WHERE a=2;
ERROR HY000: Got error 124 from storage engine
DROP TABLE t1, t2;
...@@ -376,4 +376,15 @@ select * from t3; ...@@ -376,4 +376,15 @@ select * from t3;
check table t1, t2; check table t1, t2;
drop table t1, t2, t3; drop table t1, t2, t3;
#
# BUG#21617 - crash when selecting from merge table with inconsistent
# indexes
#
CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES(2),(1);
CREATE TABLE t2(a INT, KEY(a)) ENGINE=MERGE UNION=(t1);
--error 1030
SELECT * FROM t2 WHERE a=2;
DROP TABLE t1, t2;
# End of 4.1 tests # End of 4.1 tests
...@@ -164,28 +164,22 @@ void delete_queue(QUEUE *queue) ...@@ -164,28 +164,22 @@ void delete_queue(QUEUE *queue)
void queue_insert(register QUEUE *queue, byte *element) void queue_insert(register QUEUE *queue, byte *element)
{ {
reg2 uint idx,next; reg2 uint idx, next;
int cmp; int cmp;
DBUG_ASSERT(queue->elements < queue->max_elements);
#ifndef DBUG_OFF queue->root[0]= element;
if (queue->elements < queue->max_elements)
#endif
{
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 ((cmp= 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)) &&
(cmp ^ 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;
}
queue->root[idx]=element;
} }
queue->root[idx]= element;
} }
/* Remove item from queue */ /* Remove item from queue */
...@@ -193,16 +187,12 @@ void queue_insert(register QUEUE *queue, byte *element) ...@@ -193,16 +187,12 @@ void queue_insert(register QUEUE *queue, byte *element)
byte *queue_remove(register QUEUE *queue, uint idx) byte *queue_remove(register QUEUE *queue, uint idx)
{ {
#ifndef DBUG_OFF byte *element;
if (idx >= queue->max_elements) DBUG_ASSERT(idx < queue->max_elements);
return 0; element= queue->root[++idx]; /* Intern index starts from 1 */
#endif queue->root[idx]= queue->root[queue->elements--];
{ _downheap(queue, idx);
byte *element=queue->root[++idx]; /* Intern index starts from 1 */
queue->root[idx]=queue->root[queue->elements--];
_downheap(queue,idx);
return element; return element;
}
} }
/* Fix when element on top has been replaced */ /* Fix when element on top has been replaced */
......
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