Commit d5964ba2 authored by unknown's avatar unknown

Fixes for MERGE TABLES and HEAP tables


Docs/manual.texi:
  Updated MERGE table stuff + more
extra/perror.c:
  Added missing error messages
include/myisammrg.h:
  Fixes for MERGE TABLE
include/queues.h:
  Fixes for MERGE TABLE
isam/isamlog.c:
  Fixed hard bug
myisam/mi_log.c:
  cleanup
myisam/mi_open.c:
  Fixed file name format in myisam log
myisam/myisamlog.c:
  Bug fixes
myisammrg/mymrgdef.h:
  Fixes for MERGE TABLE
myisammrg/myrg_create.c:
  Fixes for MERGE TABLE
myisammrg/myrg_open.c:
  Fixes for MERGE TABLE
myisammrg/myrg_queue.c:
  Fixes for MERGE TABLE
myisammrg/myrg_rfirst.c:
  Fixes for MERGE TABLE
myisammrg/myrg_rkey.c:
  Fixes for MERGE TABLE
myisammrg/myrg_rlast.c:
  Fixes for MERGE TABLE
myisammrg/myrg_rnext.c:
  Fixes for MERGE TABLE
myisammrg/myrg_rprev.c:
  Fixes for MERGE TABLE
myisammrg/myrg_rrnd.c:
  Fixes for MERGE TABLE
mysql.proj:
  update
mysys/queues.c:
  Fixed bug when using reverse queues
sql-bench/test-insert.sh:
  Separated some things to get better timings
sql/ha_heap.cc:
  Fixed heap table bug
sql/ha_heap.h:
  Fixed heap table bug
sql/ha_myisam.h:
  Fixed wrong max_keys
sql/ha_myisammrg.cc:
  Fixed MERGE TABLES
sql/ha_myisammrg.h:
  Fixed MERGE TABLES
sql/handler.h:
  Fix for MERGE TABLES and HEAP tables
sql/lex.h:
  Fixed MERGE TABLES
sql/mysql_priv.h:
  Cleanup of code
sql/sql_acl.cc:
  Fixed that privilege tables are flushed at start
sql/sql_lex.h:
  Fixed MERGE TABLES
sql/sql_parse.cc:
  Fixed MERGE TABLES
sql/sql_select.cc:
  Fixes for HEAP tables
sql/sql_table.cc:
  Cleanup
sql/sql_yacc.yy:
  Fixed MERGE TABLES
parent 9e37676d
This diff is collapsed.
......@@ -17,7 +17,7 @@
/* Return error-text for system error messages and nisam messages */
#define PERROR_VERSION "2.2"
#define PERROR_VERSION "2.3"
#include <global.h>
#include <my_sys.h>
......@@ -59,9 +59,11 @@ static HA_ERRORS ha_errlist[]=
{ 136,"No more room in index file" },
{ 137,"No more records (read after end of file)" },
{ 138,"Unsupported extension used for table" },
{ 139,"Too big row (>= 24 M)"},
{ 139,"Too big row (>= 16 M)"},
{ 140,"Wrong create options"},
{ 141,"Dupplicate unique on write or update"},
{ 141,"Duplicate unique on write or update"},
{ 142,"Unknown character set used"},
{ 143,"Conflicting table definition between MERGE and mapped table"},
{ 0,NullS },
};
......
......@@ -83,7 +83,8 @@ extern int myrg_rsame(MYRG_INFO *file,byte *record,int inx);
extern int myrg_update(MYRG_INFO *file,const byte *old,byte *new_rec);
extern int myrg_status(MYRG_INFO *file,MYMERGE_INFO *x,int flag);
extern int myrg_lock_database(MYRG_INFO *file,int lock_type);
extern int myrg_create(const char *name,const char **table_names);
extern int myrg_create(const char *name,const char **table_names,
my_bool fix_names);
extern int myrg_extra(MYRG_INFO *file,enum ha_extra_function function);
extern ha_rows myrg_records_in_range(MYRG_INFO *info,int inx,
const byte *start_key,uint start_key_len,
......
......@@ -53,6 +53,7 @@ void delete_queue(QUEUE *queue);
void queue_insert(QUEUE *queue,byte *element);
byte *queue_remove(QUEUE *queue,uint idx);
void _downheap(QUEUE *queue,uint idx);
#define is_queue_inited(queue) ((queue)->root != 0)
#ifdef __cplusplus
}
......
......@@ -246,7 +246,7 @@ register char ***argv;
/* Fall through */
case 'I':
case '?':
printf("%s Ver 3.1 for %s at %s\n",my_progname,SYSTEM_TYPE,
printf("%s Ver 3.2 for %s at %s\n",my_progname,SYSTEM_TYPE,
MACHINE_TYPE);
puts("TCX Datakonsult AB, by Monty, for your professional use\n");
if (version)
......@@ -325,7 +325,7 @@ static int examine_log(my_string file_name, char **table_names)
init_io_cache(&cache,file,0,READ_CACHE,start_offset,0,MYF(0));
bzero((gptr) com_count,sizeof(com_count));
init_tree(&tree,0,sizeof(file_info),(qsort_cmp) file_info_compare,0,
init_tree(&tree,0,sizeof(file_info),(qsort_cmp) file_info_compare,1,
(void(*)(void*)) file_info_free);
VOID(init_key_cache(KEY_CACHE_SIZE,(uint) (10*4*(IO_SIZE+MALLOC_OVERHEAD))));
......
......@@ -69,7 +69,8 @@ int mi_log(int activate_log)
/* Logging of records and commands on logfile */
/* All logs starts with command(1) dfile(2) process(4) result(2) */
void _myisam_log(enum myisam_log_commands command, MI_INFO *info, const byte *buffert, uint length)
void _myisam_log(enum myisam_log_commands command, MI_INFO *info,
const byte *buffert, uint length)
{
char buff[11];
int error,old_errno;
......
......@@ -524,7 +524,11 @@ MI_INFO *mi_open(const char *name, int mode, uint handle_locking)
myisam_open_list=list_add(myisam_open_list,&m_info->open_list);
pthread_mutex_unlock(&THR_LOCK_myisam);
myisam_log(MI_LOG_OPEN,m_info,share->filename,(uint) strlen(share->filename));
if (myisam_log_file >= 0)
{
intern_filename(name_buff,share->filename);
_myisam_log(MI_LOG_OPEN,m_info,name_buff,(uint) strlen(name_buff));
}
DBUG_RETURN(m_info);
err:
......
......@@ -70,7 +70,7 @@ static void printf_log(const char *str,...);
static bool cmp_filename(struct file_info *file_info,my_string name);
static uint verbose=0,update=0,test_info=0,max_files=0,re_open_count=0,
recover=0,prefix_remove=0;
recover=0,prefix_remove=0,opt_processes=0;
static my_string log_filename=0,filepath=0,write_filename=0,record_pos_file=0;
static ulong com_count[10][3],number_of_commands=(ulong) ~0L,
isamlog_process;
......@@ -199,6 +199,9 @@ static void get_options(register int *argc, register char ***argv)
update=1;
recover++;
break;
case 'P':
opt_processes=1;
break;
case 'R':
if (! *++pos)
{
......@@ -243,7 +246,7 @@ static void get_options(register int *argc, register char ***argv)
/* Fall through */
case 'I':
case '?':
printf("%s Ver 1.1 for %s at %s\n",my_progname,SYSTEM_TYPE,
printf("%s Ver 1.2 for %s at %s\n",my_progname,SYSTEM_TYPE,
MACHINE_TYPE);
puts("By Monty, for your professional use\n");
if (version)
......@@ -258,6 +261,7 @@ static void get_options(register int *argc, register char ***argv)
puts(" -o \"offset\" -p # \"remove # components from path\"");
puts(" -r \"recover\" -R \"file recordposition\"");
puts(" -u \"update\" -v \"verbose\" -w \"write file\"");
puts(" -P \"processes\"");
puts("\nOne can give a second and a third '-v' for more verbose.");
puts("Normaly one does a update (-u).");
puts("If a recover is done all writes and all possibly updates and deletes is done\nand errors are only counted.");
......@@ -322,7 +326,7 @@ static int examine_log(my_string file_name, char **table_names)
init_io_cache(&cache,file,0,READ_CACHE,start_offset,0,MYF(0));
bzero((gptr) com_count,sizeof(com_count));
init_tree(&tree,0,sizeof(file_info),(qsort_cmp) file_info_compare,0,
init_tree(&tree,0,sizeof(file_info),(qsort_cmp) file_info_compare,1,
(void(*)(void*)) file_info_free);
VOID(init_key_cache(KEY_CACHE_SIZE,(uint) (10*4*(IO_SIZE+MALLOC_OVERHEAD))));
......@@ -333,6 +337,8 @@ static int examine_log(my_string file_name, char **table_names)
isamlog_filepos=my_b_tell(&cache)-9L;
file_info.filenr= mi_uint2korr(head+1);
isamlog_process=file_info.process=(long) mi_uint4korr(head+3);
if (!opt_processes)
file_info.process=0;
result= mi_uint2korr(head+7);
if ((curr_file_info=(struct file_info*) tree_search(&tree,&file_info)))
{
......@@ -374,11 +380,17 @@ static int examine_log(my_string file_name, char **table_names)
goto err;
{
uint i;
char *pos=file_info.name,*to;
char *pos,*to;
/* Fix if old DOS files to new format */
for (pos=file_info.name; pos=strchr(pos,'\\') ; pos++)
*pos= '/';
pos=file_info.name;
for (i=0 ; i < prefix_remove ; i++)
{
char *next;
if (!(next=strchr(pos,FN_LIBCHAR)))
if (!(next=strchr(pos,'/')))
break;
pos=next+1;
}
......@@ -436,7 +448,7 @@ static int examine_log(my_string file_name, char **table_names)
if (file_info.used)
{
if (verbose && !record_pos_file)
printf_log("%s: open",file_info.show_name);
printf_log("%s: open -> %d",file_info.show_name, file_info.filenr);
com_count[command][0]++;
if (result)
com_count[command][1]++;
......
......@@ -29,4 +29,4 @@ extern pthread_mutex_t THR_LOCK_open;
#endif
int _myrg_init_queue(MYRG_INFO *info,int inx,enum ha_rkey_function search_flag);
int _myrg_finish_scan(MYRG_INFO *info, int inx, enum ha_rkey_function type);
......@@ -23,8 +23,7 @@
a NULL-pointer last
*/
int myrg_create(name,table_names)
const char *name,**table_names;
int myrg_create(const char *name, const char **table_names, my_bool fix_names)
{
int save_errno;
uint errpos;
......@@ -38,15 +37,19 @@ const char *name,**table_names;
goto err;
errpos=1;
if (table_names)
{
for ( ; *table_names ; table_names++)
{
strmov(buff,*table_names);
fn_same(buff,name,4);
if (fix_names)
fn_same(buff,name,4);
*(end=strend(buff))='\n';
if (my_write(file,*table_names,(uint) (end-buff+1),
end[1]=0;
if (my_write(file,buff,(uint) (end-buff+1),
MYF(MY_WME | MY_NABP)))
goto err;
}
}
if (my_close(file,MYF(0)))
goto err;
DBUG_RETURN(0);
......
......@@ -58,7 +58,7 @@ int handle_locking;
{
if ((end=strend(buff))[-1] == '\n')
end[-1]='\0';
if (buff[0]) /* Skipp empty lines */
if (buff[0] && buff[0] != '#') /* Skipp empty lines and comments */
{
last_isam=isam;
if (!test_if_hard_path(buff))
......@@ -93,7 +93,7 @@ int handle_locking;
m_info->options|=isam->s->options;
m_info->records+=isam->state->records;
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 (i)
isam=(MI_INFO*) (isam->open_list.next->data);
}
......
......@@ -23,31 +23,32 @@ static int queue_key_cmp(void *keyseg, byte *a, byte *b)
MI_INFO *aa=((MYRG_TABLE *)a)->table;
MI_INFO *bb=((MYRG_TABLE *)b)->table;
uint not_used;
return (_mi_key_cmp((MI_KEYSEG *)keyseg, aa->lastkey, bb->lastkey,
USE_WHOLE_KEY, SEARCH_FIND, &not_used));
int ret= _mi_key_cmp((MI_KEYSEG *)keyseg, aa->lastkey, bb->lastkey,
USE_WHOLE_KEY, SEARCH_FIND, &not_used);
return ret < 0 ? -1 : ret > 0 ? 1 : 0;
} /* queue_key_cmp */
int _myrg_init_queue(MYRG_INFO *info,int inx,enum ha_rkey_function search_flag)
{
QUEUE *q=&(info->by_key);
int error=0;
QUEUE *q= &(info->by_key);
if (!q->root)
if (!is_queue_inited(q))
{
if (init_queue(q,info->tables, 0,
(myisam_read_vec[search_flag]==SEARCH_SMALLER),
(myisam_readnext_vec[search_flag] == SEARCH_SMALLER),
queue_key_cmp,
info->open_tables->table->s->keyinfo[inx].seg))
return my_errno;
error=my_errno;
}
else
{
if (reinit_queue(q,info->tables, 0,
(myisam_read_vec[search_flag]==SEARCH_SMALLER),
(myisam_readnext_vec[search_flag] == SEARCH_SMALLER),
queue_key_cmp,
info->open_tables->table->s->keyinfo[inx].seg))
return my_errno;
error=my_errno;
}
return 0;
return error;
}
......@@ -16,7 +16,7 @@
#include "mymrgdef.h"
/* Read first row through a specfic key */
/* Read first row according to specific key */
int myrg_rfirst(MYRG_INFO *info, byte *buf, int inx)
{
......@@ -29,17 +29,17 @@ int myrg_rfirst(MYRG_INFO *info, byte *buf, int inx)
for (table=info->open_tables ; table < info->end_table ; table++)
{
err=mi_rfirst(table->table,NULL,inx);
info->last_used_table=table;
if (err == HA_ERR_END_OF_FILE)
continue;
if (err)
if ((err=mi_rfirst(table->table,NULL,inx)))
{
if (err == HA_ERR_END_OF_FILE)
continue;
return err;
}
/* adding to queue */
queue_insert(&(info->by_key),(byte *)table);
}
/* We have done a read in all tables */
info->last_used_table=table;
if (!info->by_key.elements)
return HA_ERR_END_OF_FILE;
......
......@@ -16,6 +16,17 @@
/* Read record based on a key */
/*
* HA_READ_KEY_EXACT => SEARCH_BIGGER
* HA_READ_KEY_OR_NEXT => SEARCH_BIGGER
* HA_READ_AFTER_KEY => SEARCH_BIGGER
* HA_READ_PREFIX => SEARCH_BIGGER
* HA_READ_KEY_OR_PREV => SEARCH_SMALLER
* HA_READ_BEFORE_KEY => SEARCH_SMALLER
* HA_READ_PREFIX_LAST => SEARCH_SMALLER
*/
#include "mymrgdef.h"
/* todo: we could store some additional info to speedup lookups:
......@@ -33,7 +44,7 @@ int myrg_rkey(MYRG_INFO *info,byte *record,int inx, const byte *key,
MYRG_TABLE *table;
MI_INFO *mi;
int err;
byte *buf=((search_flag == HA_READ_KEY_EXACT)?record:0);
byte *buf=((search_flag == HA_READ_KEY_EXACT) ? record: 0);
if (_myrg_init_queue(info,inx,search_flag))
return my_errno;
......@@ -52,13 +63,14 @@ int myrg_rkey(MYRG_INFO *info,byte *record,int inx, const byte *key,
{
err=_mi_rkey(mi,buf,inx,key_buff,pack_key_length,search_flag,FALSE);
}
info->last_used_table=table;
info->last_used_table=table+1;
if (err == HA_ERR_KEY_NOT_FOUND)
continue;
if (err)
{
if (err == HA_ERR_KEY_NOT_FOUND)
continue;
return err;
}
/* adding to queue */
queue_insert(&(info->by_key),(byte *)table);
......@@ -76,14 +88,3 @@ int myrg_rkey(MYRG_INFO *info,byte *record,int inx, const byte *key,
mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table;
return mi_rrnd(mi,record,mi->lastpos);
}
/*
* HA_READ_KEY_EXACT => SEARCH_BIGGER
* HA_READ_KEY_OR_NEXT => SEARCH_BIGGER
* HA_READ_AFTER_KEY => SEARCH_BIGGER
* HA_READ_PREFIX => SEARCH_BIGGER
* HA_READ_KEY_OR_PREV => SEARCH_SMALLER
* HA_READ_BEFORE_KEY => SEARCH_SMALLER
* HA_READ_PREFIX_LAST => SEARCH_SMALLER
*/
......@@ -24,22 +24,22 @@ int myrg_rlast(MYRG_INFO *info, byte *buf, int inx)
MI_INFO *mi;
int err;
if (_myrg_init_queue(info,inx,HA_READ_KEY_OR_PREV))
if (_myrg_init_queue(info,inx, HA_READ_KEY_OR_PREV))
return my_errno;
for (table=info->open_tables ; table < info->end_table ; table++)
{
err=mi_rlast(table->table,NULL,inx);
info->last_used_table=table;
if (err == HA_ERR_END_OF_FILE)
continue;
if (err)
if ((err=mi_rlast(table->table,NULL,inx)))
{
if (err == HA_ERR_END_OF_FILE)
continue;
return err;
}
/* adding to queue */
queue_insert(&(info->by_key),(byte *)table);
}
/* We have done a read in all tables */
info->last_used_table=table;
if (!info->by_key.elements)
return HA_ERR_END_OF_FILE;
......
......@@ -22,22 +22,21 @@
int myrg_rnext(MYRG_INFO *info, byte *buf, int inx)
{
MYRG_TABLE *table;
MI_INFO *mi;
byte *key_buff;
uint pack_key_length;
int err;
MI_INFO *mi;
/* at first, do rnext for the table found before */
err=mi_rnext(info->current_table->table,NULL,inx);
if (err == HA_ERR_END_OF_FILE)
if ((err=mi_rnext(info->current_table->table,NULL,inx)))
{
queue_remove(&(info->by_key),0);
if (!info->by_key.elements)
return HA_ERR_END_OF_FILE;
if (err == HA_ERR_END_OF_FILE)
{
queue_remove(&(info->by_key),0);
if (!info->by_key.elements)
return HA_ERR_END_OF_FILE;
}
else
return err;
}
else if (err)
return err;
else
{
/* Found here, adding to queue */
......@@ -46,30 +45,42 @@ int myrg_rnext(MYRG_INFO *info, byte *buf, int inx)
}
/* next, let's finish myrg_rkey's initial scan */
table=info->last_used_table+1;
if ((err=_myrg_finish_scan(info, inx, HA_READ_KEY_OR_NEXT)))
return err;
/* now, mymerge's read_next is as simple as one queue_top */
mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table;
return mi_rrnd(mi,buf,mi->lastpos);
}
/* let's finish myrg_rkey's initial scan */
int _myrg_finish_scan(MYRG_INFO *info, int inx, enum ha_rkey_function type)
{
int err;
MYRG_TABLE *table=info->last_used_table;
if (table < info->end_table)
{
mi=info->last_used_table->table;
key_buff=(byte*) mi->lastkey+mi->s->base.max_key_length;
pack_key_length=mi->last_rkey_length;
MI_INFO *mi= table[-1].table;
byte *key_buff=(byte*) mi->lastkey+mi->s->base.max_key_length;
uint pack_key_length= mi->last_rkey_length;
for (; table < info->end_table ; table++)
{
mi=table->table;
err=_mi_rkey(mi,NULL,inx,key_buff,pack_key_length,HA_READ_KEY_OR_NEXT,FALSE);
info->last_used_table=table;
if (err == HA_ERR_KEY_NOT_FOUND)
continue;
if (err)
return err;
if ((err=_mi_rkey(mi,NULL,inx,key_buff,pack_key_length,
type,FALSE)))
{
if (err == HA_ERR_KEY_NOT_FOUND) /* If end of file */
continue;
return err;
}
/* Found here, adding to queue */
queue_insert(&(info->by_key),(byte *)table);
queue_insert(&(info->by_key),(byte *) table);
}
/* All tables are now used */
info->last_used_table=table;
}
/* now, mymerge's read_next is as simple as one queue_top */
mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table;
return mi_rrnd(mi,buf,mi->lastpos);
return 0;
}
......@@ -22,22 +22,21 @@
int myrg_rprev(MYRG_INFO *info, byte *buf, int inx)
{
MYRG_TABLE *table;
MI_INFO *mi;
byte *key_buff;
uint pack_key_length;
int err;
MI_INFO *mi;
/* at first, do rnext for the table found before */
err=mi_rprev(info->current_table->table,NULL,inx);
if (err == HA_ERR_END_OF_FILE)
/* at first, do rprev for the table found before */
if ((err=mi_rprev(info->current_table->table,NULL,inx)))
{
queue_remove(&(info->by_key),0);
if (!info->by_key.elements)
return HA_ERR_END_OF_FILE;
if (err == HA_ERR_END_OF_FILE)
{
queue_remove(&(info->by_key),0);
if (!info->by_key.elements)
return HA_ERR_END_OF_FILE;
}
else
return err;
}
else if (err)
return err;
else
{
/* Found here, adding to queue */
......@@ -46,28 +45,8 @@ int myrg_rprev(MYRG_INFO *info, byte *buf, int inx)
}
/* next, let's finish myrg_rkey's initial scan */
table=info->last_used_table+1;
if (table < info->end_table)
{
mi=info->last_used_table->table;
key_buff=(byte*) mi->lastkey+mi->s->base.max_key_length;
pack_key_length=mi->last_rkey_length;
for (; table < info->end_table ; table++)
{
mi=table->table;
err=_mi_rkey(mi,NULL,inx,key_buff,pack_key_length,
HA_READ_KEY_OR_PREV,FALSE);
info->last_used_table=table;
if (err == HA_ERR_KEY_NOT_FOUND)
continue;
if (err)
return err;
/* Found here, adding to queue */
queue_insert(&(info->by_key),(byte *)table);
}
}
if ((err=_myrg_finish_scan(info, inx, HA_READ_KEY_OR_PREV)))
return err;
/* now, mymerge's read_prev is as simple as one queue_top */
mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table;
......
......@@ -84,10 +84,10 @@ int myrg_rrnd(MYRG_INFO *info,byte *buf,ulonglong filepos)
info->end_table-1,filepos);
isam_info=info->current_table->table;
isam_info->update&= HA_STATE_CHANGED;
return ((*isam_info->s->read_rnd)(isam_info,(byte*) buf,
(ha_rows) (filepos -
info->current_table->file_offset),
0));
return ((*isam_info->s->read_rnd)
(isam_info, (byte*) buf,
(ha_rows) (filepos - info->current_table->file_offset),
0));
}
......
No preview for this file type
......@@ -25,7 +25,7 @@
#include <queues.h>
/* The actuall code for handling queues */
/* Init queue */
int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
pbool max_at_top, int (*compare) (void *, byte *, byte *),
......@@ -44,6 +44,12 @@ int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
DBUG_RETURN(0);
}
/*
Reinitialize queue for new usage; Note that you can't currently resize
the number of elements! If you need this, fix it :)
*/
int reinit_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
pbool max_at_top, int (*compare) (void *, byte *, byte *),
void *first_cmp_arg)
......@@ -78,6 +84,7 @@ void delete_queue(QUEUE *queue)
void queue_insert(register QUEUE *queue, byte *element)
{
reg2 uint idx,next;
int cmp;
#ifndef DBUG_OFF
if (queue->elements < queue->max_elements)
......@@ -86,10 +93,12 @@ void queue_insert(register QUEUE *queue, byte *element)
queue->root[0]=element;
idx= ++queue->elements;
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)
/* 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)
{
queue->root[idx]=queue->root[next];
idx=next;
......
......@@ -348,12 +348,12 @@ print " for select_diff_key ($count:$rows): " .
# Test select that is very popular when using ODBC
check_or_range("id","select_range_prefix");
check_or_range("id3","select_range");
check_or_range("id3","select_range_key2");
# Check reading on direct key on id and id3
check_select_key("id","select_key_prefix");
check_select_key("id3","select_key");
check_select_key("id3","select_key_key2");
####
#### A lot of simple selects on ranges
......@@ -403,7 +403,7 @@ check_select_key("id3","select_key");
print "\nTest of compares with simple ranges\n";
check_select_range("id","select_range_prefix");
check_select_range("id3","select_range");
check_select_range("id3","select_range_key2");
####
#### Some group queries
......@@ -1107,20 +1107,28 @@ if ($server->small_rollback_segment())
# Delete everything from table
#
print "Deleting everything from table\n";
print "Deleting rows from the table\n";
$loop_time=new Benchmark;
$count=0;
for ($i=0 ; $i < 128 ; $i++)
{
$dbh->do("delete from bench1 where field1 = $i") or die $DBI::errstr;
}
$end_time=new Benchmark;
print "Time for delete_big_many_keys ($count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
print "Deleting everything from table\n";
$count=1;
if ($opt_fast)
{
$dbh->do("delete from bench1 where field1 = 0") or die $DBI::errstr;
$dbh->do("delete from bench1") or die $DBI::errstr;
$count+=2;
}
else
{
$dbh->do("delete from bench1 where field1 = 0") or die $DBI::errstr;
$dbh->do("delete from bench1 where field1 > 0") or die $DBI::errstr;
$count+=2;
}
if ($opt_lock_tables)
......@@ -1129,7 +1137,7 @@ if ($opt_lock_tables)
}
$end_time=new Benchmark;
print "Time for delete_big_many_keys ($count): " .
print "Time for delete_all_many_keys ($count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
$sth = $dbh->do("drop table bench1") or die $DBI::errstr;
......
......@@ -261,7 +261,7 @@ ha_rows ha_heap::records_in_range(int inx,
if (start_key_len != end_key_len ||
start_key_len != pos->key_length ||
start_search_flag != HA_READ_KEY_EXACT ||
end_search_flag != HA_READ_KEY_EXACT)
end_search_flag != HA_READ_AFTER_KEY)
return HA_POS_ERROR; // Can't only use exact keys
return 10; // Good guess
}
......
......@@ -33,14 +33,15 @@ class ha_heap: public handler
const char *table_type() const { return "HEAP"; }
const char **bas_ext() const;
ulong option_flag() const
{ return (HA_READ_RND_SAME+HA_NO_INDEX+HA_BINARY_KEYS+HA_WRONG_ASCII_ORDER+
HA_KEYPOS_TO_RNDPOS+HA_NO_BLOBS+HA_REC_NOT_IN_SEQ); }
{ return (HA_READ_RND_SAME | HA_NO_INDEX | HA_ONLY_WHOLE_INDEX |
HA_WRONG_ASCII_ORDER | HA_KEYPOS_TO_RNDPOS | HA_NO_BLOBS |
HA_REC_NOT_IN_SEQ); }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return MAX_KEY; }
uint max_key_parts() const { return MAX_REF_PARTS; }
uint max_key_length() const { return HA_MAX_REC_LENGTH; }
virtual double scan_time() { return (double) (records+deleted) / 100.0; }
virtual double read_time(ha_rows rows) { return (double) rows / 100.0; }
virtual double scan_time() { return (double) (records+deleted) / 20.0+10; }
virtual double read_time(ha_rows rows) { return (double) rows / 20.0+1; }
virtual bool fast_key_read() { return 1;}
int open(const char *name, int mode, int test_if_locked);
......
......@@ -45,7 +45,7 @@ class ha_myisam: public handler
const char **bas_ext() const;
ulong option_flag() const { return int_option_flag; }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return 1; }
uint max_keys() const { return MI_MAX_KEY; }
uint max_key_parts() const { return MAX_REF_PARTS; }
uint max_key_length() const { return MAX_KEY_LENGTH; }
......
......@@ -180,11 +180,7 @@ void ha_myisammrg::info(uint flag)
mean_rec_length=info.reclength;
block_size=0;
update_time=0;
#if SIZEOF_OFF_T > 4
ref_length=6; // Should be big enough
#else
ref_length=4;
#endif
}
......@@ -228,6 +224,16 @@ THR_LOCK_DATA **ha_myisammrg::store_lock(THD *thd,
int ha_myisammrg::create(const char *name, register TABLE *form,
HA_CREATE_INFO *create_info)
{
char buff[FN_REFLEN];
return myrg_create(fn_format(buff,name,"","",2+4+16),0);
char buff[FN_REFLEN],**table_names,**pos;
TABLE_LIST *tables= (TABLE_LIST*) create_info->merge_list.first;
DBUG_ENTER("ha_myisammrg::create");
if (!(table_names= (char**) sql_alloc((create_info->merge_list.elements+1)*
sizeof(char*))))
DBUG_RETURN(1);
for (pos=table_names ; tables ; tables=tables->next)
*pos++= tables->real_name;
*pos=0;
DBUG_RETURN(myrg_create(fn_format(buff,name,"","",2+4+16),
(const char **) table_names, (my_bool) 0));
}
......@@ -32,15 +32,19 @@ class ha_myisammrg: public handler
~ha_myisammrg() {}
const char *table_type() const { return "MRG_MyISAM"; }
const char **bas_ext() const;
ulong option_flag() const { return HA_REC_NOT_IN_SEQ+HA_READ_NEXT+
HA_READ_PREV+HA_READ_RND_SAME+HA_HAVE_KEY_READ_ONLY+
HA_KEYPOS_TO_RNDPOS+HA_READ_ORDER+
HA_LASTKEY_ORDER+HA_READ_NOT_EXACT_KEY+
HA_LONGLONG_KEYS+HA_NULL_KEY+HA_BLOB_KEY; }
ulong option_flag() const
{ return (HA_REC_NOT_IN_SEQ | HA_READ_NEXT |
HA_READ_PREV | HA_READ_RND_SAME |
HA_HAVE_KEY_READ_ONLY |
HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER |
HA_LASTKEY_ORDER | HA_READ_NOT_EXACT_KEY |
HA_LONGLONG_KEYS | HA_NULL_KEY | HA_BLOB_KEY); }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return 1; }
uint max_keys() const { return MI_MAX_KEY; }
uint max_key_parts() const { return MAX_REF_PARTS; }
uint max_key_length() const { return MAX_KEY_LENGTH; }
virtual double scan_time()
{ return ulonglong2double(data_file_length) / IO_SIZE + file->tables; }
int open(const char *name, int mode, int test_if_locked);
int close(void);
......
......@@ -47,7 +47,7 @@
if database is updated after read) */
#define HA_REC_NOT_IN_SEQ 64 /* ha_info don't return recnumber;
It returns a position to ha_r_rnd */
#define HA_BINARY_KEYS 128 /* Keys must be exact */
#define HA_ONLY_WHOLE_INDEX 128 /* Can't use part key searches */
#define HA_RSAME_NO_INDEX 256 /* RSAME can't restore index */
#define HA_WRONG_ASCII_ORDER 512 /* Can't use sorting through key */
#define HA_HAVE_KEY_READ_ONLY 1024 /* Can read only keys (no record) */
......@@ -127,6 +127,7 @@ typedef struct st_ha_create_information
ulong raid_chunksize;
bool if_not_exists;
ulong used_fields;
SQL_LIST merge_list;
} HA_CREATE_INFO;
......
......@@ -297,11 +297,12 @@ static SYMBOL symbols[] = {
{ "TRAILING", SYM(TRAILING),0,0},
{ "TO", SYM(TO_SYM),0,0},
{ "TYPE", SYM(TYPE_SYM),0,0},
{ "USE", SYM(USE_SYM),0,0},
{ "USING", SYM(USING),0,0},
{ "UNION", SYM(UNION_SYM),0,0},
{ "UNIQUE", SYM(UNIQUE_SYM),0,0},
{ "UNLOCK", SYM(UNLOCK_SYM),0,0},
{ "UNSIGNED", SYM(UNSIGNED),0,0},
{ "USE", SYM(USE_SYM),0,0},
{ "USING", SYM(USING),0,0},
{ "UPDATE", SYM(UPDATE_SYM),0,0},
{ "USAGE", SYM(USAGE),0,0},
{ "VALUES", SYM(VALUES),0,0},
......
......@@ -78,7 +78,11 @@ void sql_element_free(void *ptr);
// The following is used to decide if MySQL should use table scanning
// instead of reading with keys. The number says how many evaluation of the
// WHERE clause is comparable to reading one extra row from a table.
#define TIME_FOR_COMPARE 5 // 5 compares == one read
#define TIME_FOR_COMPARE 5 // 5 compares == one read
// Number of rows in a reference table when refereed through a not unique key.
// This value is only used when we don't know anything about the key
// distribution.
#define MATCHING_ROWS_IN_OTHER_TABLE 10
/* Don't pack string keys shorter than this (if PACK_KEYS=1 isn't used) */
#define KEY_DEFAULT_PACK_LENGTH 8
......
......@@ -1905,6 +1905,7 @@ int grant_init (void)
{
t_table->file->index_end();
mysql_unlock_tables(thd, lock);
thd->version--; // Force close to free memory
close_thread_tables(thd);
delete thd;
DBUG_RETURN(0); // Empty table is ok!
......
......@@ -94,16 +94,9 @@ typedef struct st_lex {
LEX_YYSTYPE yylval;
uchar *ptr,*tok_start,*tok_end,*end_of_query;
ha_rows select_limit,offset_limit;
bool create_refs,drop_primary,drop_if_exists,local_file,
in_comment,ignore_space,verbose;
enum_sql_command sql_command;
enum lex_states next_state;
ulong options;
uint in_sum_expr,grant,grant_tot_col,which_columns, sort_default;
char *length,*dec,*change,*name;
String *wild;
sql_exchange *exchange;
thr_lock_type lock_option;
List<List_item> expr_list;
List<List_item> when_list;
......@@ -124,17 +117,25 @@ typedef struct st_lex {
create_field *last_field;
Item *where,*having,*default_value;
enum enum_duplicates duplicates;
ulong thread_id,type;
HA_CREATE_INFO create_info;
CONVERT *convert_set;
LEX_USER *grant_user;
LEX_USER *grant_user;
char *db,*db1,*table1,*db2,*table2; /* For outer join using .. */
gptr yacc_yyss,yacc_yyvs;
THD *thd;
udf_func udf;
HA_CHECK_OPT check_opt; // check/repair options
LEX_MASTER_INFO mi; // used by CHANGE MASTER
HA_CHECK_OPT check_opt; // check/repair options
HA_CREATE_INFO create_info;
LEX_MASTER_INFO mi; // used by CHANGE MASTER
ulong thread_id,type;
ulong options;
enum_sql_command sql_command;
enum lex_states next_state;
enum enum_duplicates duplicates;
uint in_sum_expr,grant,grant_tot_col,which_columns, sort_default;
thr_lock_type lock_option;
bool create_refs,drop_primary,drop_if_exists,local_file;
bool in_comment,ignore_space,verbose;
} LEX;
......
......@@ -38,8 +38,9 @@ extern "C" pthread_mutex_t THR_LOCK_keycache;
extern "C" int gethostname(char *name, int namelen);
#endif
static bool check_table_access(THD *thd,uint want_access,TABLE_LIST *tables);
static bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables);
static bool check_db_used(THD *thd,TABLE_LIST *tables);
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
static bool check_dup(THD *thd,const char *db,const char *name,
TABLE_LIST *tables);
static void mysql_init_query(THD *thd);
......@@ -504,9 +505,9 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
if(!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
DBUG_RETURN(1);
if(check_access(thd, SELECT_ACL, db, &table_list->grant.privilege))
if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege))
goto err;
if(grant_option && check_grant(thd, SELECT_ACL, table_list))
if (grant_option && check_grant(thd, SELECT_ACL, table_list))
goto err;
thd->free_list = 0;
......@@ -988,10 +989,12 @@ mysql_execute_command(void)
break;
case SQLCOM_CREATE_TABLE:
#ifdef DEMO_VERSION
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);
#else
if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege))
if (!tables->db)
tables->db=thd->db;
if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege) ||
check_merge_table_access(thd, tables->db,
(TABLE_LIST *)
lex->create_info.merge_list.first))
goto error; /* purecov: inspected */
if (grant_option)
{
......@@ -1072,7 +1075,6 @@ mysql_execute_command(void)
if (grant_option && check_grant(thd,INDEX_ACL,tables))
goto error;
res = mysql_create_index(thd, tables, lex->key_list);
#endif
break;
case SQLCOM_SLAVE_START:
......@@ -1082,7 +1084,6 @@ mysql_execute_command(void)
stop_slave(thd);
break;
case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
......@@ -1096,11 +1097,16 @@ mysql_execute_command(void)
res=0;
break;
}
if (!tables->db)
tables->db=thd->db;
if (!lex->db)
lex->db=tables->db;
if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege) ||
check_access(thd,INSERT_ACL | CREATE_ACL,lex->db,&priv))
goto error; /* purecov: inspected */
check_access(thd,INSERT_ACL | CREATE_ACL,lex->db,&priv) ||
check_merge_table_access(thd, tables->db,
(TABLE_LIST *)
lex->create_info.merge_list.first))
goto error; /* purecov: inspected */
if (!tables->db)
tables->db=thd->db;
if (grant_option)
......@@ -1354,7 +1360,7 @@ mysql_execute_command(void)
res = mysql_drop_index(thd, tables, lex->drop_list);
break;
case SQLCOM_SHOW_DATABASES:
#if defined(DONT_ALLOW_SHOW_COMMANDS) || defined(DEMO_VERSION)
#if defined(DONT_ALLOW_SHOW_COMMANDS)
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
......@@ -1810,6 +1816,22 @@ static bool check_db_used(THD *thd,TABLE_LIST *tables)
}
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list)
{
int error=0;
if (table_list)
{
/* Force all tables to use the current database */
TABLE_LIST *tmp;
for (tmp=table_list; tmp ; tmp=tmp->next)
tmp->db=db;
error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
table_list);
}
return error;
}
/****************************************************************************
Check stack size; Send error if there isn't enough stack to continue
****************************************************************************/
......@@ -2462,7 +2484,7 @@ static int start_slave(THD* thd , bool net_report)
if(!thd) thd = current_thd;
NET* net = &thd->net;
const char* err = 0;
if(check_access(thd, PROCESS_ACL, any_db))
if (check_access(thd, PROCESS_ACL, any_db))
return 1;
pthread_mutex_lock(&LOCK_slave);
if(!slave_running)
......@@ -2497,7 +2519,7 @@ static int stop_slave(THD* thd, bool net_report )
NET* net = &thd->net;
const char* err = 0;
if(check_access(thd, PROCESS_ACL, any_db))
if (check_access(thd, PROCESS_ACL, any_db))
return 1;
pthread_mutex_lock(&LOCK_slave);
......
......@@ -942,7 +942,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
}
/* Approximate found rows and time to read them */
s->found_records=s->records=s->table->file->records;
s->read_time=(ha_rows) ((s->table->file->data_file_length)/IO_SIZE)+1;
s->read_time=(ha_rows) s->table->file->scan_time();
/* Set a max range of how many seeks we can expect when using keys */
s->worst_seeks= (double) (s->read_time*2);
......@@ -1419,18 +1419,18 @@ update_ref_and_keys(DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,uint tables,
for (i=0 ; i < keyuse->elements-1 ; i++,use++)
{
if (!use->used_tables)
use->table->const_key_parts[use->key]|=
use->table->const_key_parts[use->key] |=
(key_part_map) 1 << use->keypart;
if (use->keypart != FT_KEYPART)
{
if (use->key == prev->key && use->table == prev->table)
{
if (prev->keypart+1 < use->keypart ||
prev->keypart == use->keypart && found_eq_constant)
continue; /* remove */
}
else if (use->keypart != 0) // First found must be 0
continue;
if (use->key == prev->key && use->table == prev->table)
{
if (prev->keypart+1 < use->keypart ||
prev->keypart == use->keypart && found_eq_constant)
continue; /* remove */
}
else if (use->keypart != 0) // First found must be 0
continue;
}
*save_pos= *use;
......@@ -1532,7 +1532,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
double best_records=DBL_MAX;
/* Test how we can use keys */
rec= s->records/10; /* Assume 10 records/key */
rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; /* Assumed records/key */
for (keyuse=s->keyuse ; keyuse->table == table ;)
{
key_map found_part=0;
......@@ -1571,7 +1571,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
if (map == 1) // Only one table
{
TABLE *tmp_table=join->all_tables[tablenr];
if (rec > tmp_table->file->records)
if (rec > tmp_table->file->records && rec > 100)
rec=max(tmp_table->file->records,100);
}
}
......@@ -1615,12 +1615,12 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
}
else
{
if (!found_ref) // If not const key
{
if (!found_ref)
{ // We found a const key
if (table->quick_keys & ((key_map) 1 << key))
records= (double) table->quick_rows[key];
else
records= (double) s->records; // quick_range couldn't use key!
records= (double) s->records/rec; // quick_range couldn't use key!
}
else
{
......@@ -1654,7 +1654,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
** than a not unique key
** Set tmp to (previous record count) * (records / combination)
*/
if (found_part & 1)
if ((found_part & 1) &&
!(table->file->option_flag() & HA_ONLY_WHOLE_INDEX))
{
uint max_key_part=max_part_bit(found_part);
/* Check if quick_range could determinate how many rows we
......
......@@ -176,7 +176,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_ENTER("mysql_create_table");
/*
** Check for dupplicate fields and check type of table to create
** Check for duplicate fields and check type of table to create
*/
if (!fields.elements)
......@@ -302,7 +302,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
bool primary_key=0,unique_key=0;
Key *key;
uint tmp;
tmp=max(file->max_keys(), MAX_KEY);
tmp=min(file->max_keys(), MAX_KEY);
if (key_count > tmp)
{
......
......@@ -262,6 +262,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token UDF_RETURNS_SYM
%token UDF_SONAME_SYM
%token UDF_SYM
%token UNION_SYM
%token UNIQUE_SYM
%token USAGE
%token USE_SYM
......@@ -712,6 +713,18 @@ create_table_option:
| RAID_TYPE EQ raid_types { Lex->create_info.raid_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
| RAID_CHUNKS EQ ULONG_NUM { Lex->create_info.raid_chunks= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
| RAID_CHUNKSIZE EQ ULONG_NUM { Lex->create_info.raid_chunksize= $3*RAID_BLOCK_SIZE; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
| UNION_SYM EQ '(' table_list ')'
{
/* Move the union list to the merge_list */
LEX *lex=Lex;
TABLE_LIST *table_list= (TABLE_LIST*) lex->table_list.first;
lex->create_info.merge_list= lex->table_list;
lex->create_info.merge_list.elements--;
lex->create_info.merge_list.first= (byte*) (table_list->next);
lex->table_list.elements=1;
lex->table_list.next= (byte**) &(table_list->next);
table_list->next=0;
}
table_types:
ISAM_SYM { $$= DB_TYPE_ISAM; }
......
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