diff --git a/Docs/manual.texi b/Docs/manual.texi index cba039b6a9c946971c5b8c9ce94c61f4d4cc432b..183c58f23c2ccfb45cf6442d487091c65222e7a1 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -195,8 +195,8 @@ Installing a MySQL binary distribution System-specific issues -* Binary notes-Linux:: Linux notes -* Binary notes-HP-UX:: HP-UX notes +* Binary notes-Linux:: Linux notes for binary distribution +* Binary notes-HP-UX:: HP-UX notes for binary distribution Installing a MySQL source distribution @@ -259,6 +259,7 @@ Windows notes * Windows and SSH:: Connecting to a remote @strong{MySQL} from Windows with SSH * Windows symbolic links:: Splitting data across different disks under Win32 * Windows compiling:: Compiling MySQL clients on Windows. +* Windows and BDB tables.:: * Windows vs Unix:: @strong{MySQL}-Windows compared to Unix @strong{MySQL} Post-installation setup and testing @@ -4568,8 +4569,8 @@ files. @subsection System-specific issues @menu -* Binary notes-Linux:: Linux notes -* Binary notes-HP-UX:: HP-UX notes +* Binary notes-Linux:: Linux notes for binary distribution +* Binary notes-HP-UX:: HP-UX notes for binary distribution @end menu The following sections indicate some of the issues that have been observed @@ -4577,7 +4578,7 @@ on particular systems when installing @strong{MySQL} from a binary distribution. @node Binary notes-Linux, Binary notes-HP-UX, Binary install system issues, Binary install system issues -@subsubsection Linux notes +@subsubsection Linux notes for binary distribution @strong{MySQL} needs at least Linux 2.0. @@ -4653,7 +4654,7 @@ and clients on the same machine. We hope that the @code{Linux 2.4} kernel will fix this problem in the future. @node Binary notes-HP-UX, , Binary notes-Linux, Binary install system issues -@subsubsection HP-UX notes +@subsubsection HP-UX notes for binary distribution Some of the binary distributions of @strong{MySQL} for HP-UX is distributed as an HP depot file and as a tar file. To use the depot @@ -7203,6 +7204,7 @@ is also described in the @file{README} file that comes with the * Windows and SSH:: Connecting to a remote @strong{MySQL} from Windows with SSH * Windows symbolic links:: Splitting data across different disks under Win32 * Windows compiling:: Compiling MySQL clients on Windows. +* Windows and BDB tables.:: * Windows vs Unix:: @strong{MySQL}-Windows compared to Unix @strong{MySQL} @end menu @@ -7511,7 +7513,7 @@ should create the file @file{C:\mysql\data\foo.sym} that should contains the text @code{D:\data\foo}. After this, all tables created in the database @code{foo} will be created in @file{D:\data\foo}. -@node Windows compiling, Windows vs Unix, Windows symbolic links, Windows +@node Windows compiling, Windows and BDB tables., Windows symbolic links, Windows @subsection Compiling MySQL clients on Windows. In your source files, you should include @file{windows.h} before you include @@ -7531,7 +7533,17 @@ with the static @file{mysqlclient.lib} library. Note that as the mysqlclient libraries are compiled as threaded libraries, you should also compile your code to be multi-threaded! -@node Windows vs Unix, , Windows compiling, Windows +@node Windows and BDB tables., Windows vs Unix, Windows compiling, Windows +@subsection Windows and BDB tables. + +We are working on removing the requirement that one must have a primary +key in a BDB table; As soon as this is fixed we will throughly test the +BDB interface by running the @strong{MySQL} benchmark + our internal +test suite on it. When the above is done we will start release binary +distributions (for windows and Unix) of @strong{MySQL} that will include +support for BDB tables. + +@node Windows vs Unix, , Windows and BDB tables., Windows @subsection MySQL-Windows compared to Unix MySQL @strong{MySQL}-Windows has by now proven itself to be very stable. This version @@ -16445,6 +16457,7 @@ or PASSWORD = "string" or DELAY_KEY_WRITE = @{0 | 1@} or ROW_FORMAT= @{ default | dynamic | static | compressed @} or RAID_TYPE= @{1 | STRIPED | RAID0 @} RAID_CHUNKS=# RAID_CHUNKSIZE=#; +or UNION = (table_name,[table_name...]) select_statement: [IGNORE | REPLACE] SELECT ... (Some legal select statement) @@ -16742,8 +16755,14 @@ If you specify @code{RAID_TYPE=STRIPED} for a @code{MyISAM} table, to the data file, the @code{RAID} handler will map the first @code{RAID_CHUNKSIZE} *1024 bytes to the first file, the next @code{RAID_CHUNKSIZE} *1024 bytes to the next file and so on. -@end itemize +@code{UNION} is used when you want to use a collection of identical +tables as one. This only works with MERGE tables. @xref{MERGE}. + +For the moment you need to have @code{SELECT}, @code{UPDATE} and +@code{DELETE} privileges on the tables you map to a @code{MERGE} table. +All mapped tables must be in the same database as the @code{MERGE} table. +@end itemize @node Silent column changes, , CREATE TABLE, CREATE TABLE @subsection Silent column specification changes @@ -20633,9 +20652,10 @@ missing is a way from the SQL prompt to say which tables are part of the @code{MERGE} table. A @code{MERGE} table is a collection of identical @code{MyISAM} tables -that can be used as one. You can only @code{SELECT} from the collection -of tables. If you @code{DROP} the @code{MERGE} table, you are only -dropping the @code{MERGE} specification. +that can be used as one. You can only @code{SELECT}, @code{DELETE} and +@code{UPDATE} from the collection of tables. If you @code{DROP} the +@code{MERGE} table, you are only dropping the @code{MERGE} +specification. With identical tables we mean that all tables are created with identical column information. Some of the tables can be compressed with @@ -20646,7 +20666,10 @@ definition file and a @code{.MRG} table list file. The @code{.MRG} just contains a list of the index files (@code{.MYI} files) that should be used as one. -@code{MERGE} tables helps you solve the following problems: +For the moment you need to have @code{SELECT}, @code{UPDATE} and +@code{DELETE} privileges on the tables you map to a @code{MERGE} table. + +@code{MERGE} tables can help you solve the following problems: @itemize @bullet @item @@ -20671,13 +20694,22 @@ are mapped to a @code{MERGE} file than trying to repair a real big file. Instant mapping of many files as one; A @code{MERGE} table uses the index of the individual tables; It doesn't need an index of its one. This makes @code{MERGE} table collections VERY fast to make or remap. +@item +If you have a set of tables which you join to a big tables on demand or +batch, you should instead create a @code{MERGE} table on them on demand. +This is much faster and will save a lot of disk space. +@item +Go around the file size limit for the operating system. @end itemize The disadvantages with @code{MERGE} tables are: @itemize @bullet @item -@code{MERGE} tables are read-only. +You can't use @code{INSERT} on @code{MERGE} tables, as @strong{MySQL} can't know +in which of the tables we should insert the row. +@item +You can only use identical @code{MyISAM} tables for a @code{MERGE} table. @item @code{MERGE} tables uses more file descriptors: If you are using a @strong{MERGE} that maps over 10 tables and 10 users are using this, you @@ -20703,18 +20735,15 @@ CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY, message CHAR(20)); CREATE TABLE t2 (a INT AUTO_INCREMENT PRIMARY KEY, message CHAR(20)); INSERT INTO t1 (message) VALUES ("Testing"),("table"),("t1"); INSERT INTO t2 (message) VALUES ("Testing"),("table"),("t2"); -CREATE TABLE total (a INT NOT NULL, message CHAR(20), KEY(a)) TYPE=MERGE; +CREATE TABLE total (a INT NOT NULL, message CHAR(20), KEY(a)) TYPE=MERGE UNION=(t1,t2); @end example Note that we didn't create an @code{UNIQUE} or @code{PRIMARY KEY} in the @code{total} table as the key isn't going to be unique in the @code{total} table. -(We plan to in the future add the information in the @code{MERGE} handler -that unique keys are not necessarily unique in the @code{MERGE} table.) - -Now you have to use tool (editor, unix command...) to insert the file -names into the 'total' table: +Note that you can also manipulate the @code{.MRG} file directly from +the outside of the @code{MySQL} server: @example shell> cd /mysql-data-directory/current-database @@ -20737,13 +20766,11 @@ mysql> select * from total; +---+---------+ @end example -To remap a @code{MERGE} table you must either @code{DROP} it and recreate it -or change the @code{.MRG} file and issue a @code{FLUSH TABLE} on the -@code{MERGE} table to force the handler to read the new definition file. - -You can also put full paths to the index files in the @code{.MRG} file; If -you don't do this, the @code{MERGE} handler assumes that the index files -are in the same directory as the @code{.MRG} file. +To remap a @code{MERGE} table you must either @code{DROP} it and +recreate it, use @code{ALTER TABLE} with a new @code{UNION} +specification or change the @code{.MRG} file and issue a @code{FLUSH +TABLE} on the @code{MERGE} table and all underlying tables to force the +handler to read the new definition file. @node ISAM, HEAP, MERGE, Table types @section ISAM tables @@ -28799,6 +28826,48 @@ string to a time. This would be great if the source was a text file, but is plain stupid when the source is an ODBC connection that reports exact types for each column. @end itemize +@item Word + +To retrieve data from @strong{MySQL}to Word/Excel documents, you need to +use the @code{MyODBC} driver and the Add-in Microsoft Query help. + +For example, create a db with a table with 2 columns text. + +@itemize @bullet +@item +Insert rows using the mysql client command line tool. +@item +Create a DSN file using the MyODBC driver e.g. my for the db above. +@item +Open the Word application. +@item +Create a blank new documentation. +@item +Using the tool bar called Database, press the button insert database. +@item +Press the button Get Data. +@item +At the right hand of the screen Get Data, press the button Ms Query. +@item +In the Ms Query create a New Data Source using the DSN file my. +@item +Select the new query. +@item +Select the columns that you want. +@item +Make a filter if you want. +@item +Make a Sort if you want. +@item +Select Return Data to Microsoft Word. +@item +Click Finish. +@item +Click Insert data and select the records. +@item +Click OK and you see the rows in your Word document. +@end itemize + @item odbcadmin Test program for ODBC. @item Delphi @@ -36224,6 +36293,11 @@ though, so 3.23 is not released as a stable version yet. @appendixsubsec Changes in release 3.23.25 @itemize @bullet @item +@code{HEAP} tables didn't use keys properly. (Bug from 3.23.23) +@item +Added better support for @code{MERGE} tables (keys, mapping, creation, +documentation...). @xref{MERGE}. +@item Fixed bug in mysqldump from 3.23 which caused that some @code{CHAR} columns wheren't quoted. @item @@ -40304,6 +40378,8 @@ Fixed @code{DISTINCT} with calculated columns. @itemize @bullet @item +For the moment @code{MATCH} only works with @code{SELECT} statements. +@item You cannot build in another directory when using MIT-pthreads. Because this requires changes to MIT-pthreads, we are not likely to fix this. @@ -40391,6 +40467,9 @@ the error value 'empty string', with numeric value 0. @item If you execute a @code{PROCEDURE} on a query with returns an empty set then in some cases the @code{PROCEDURE} will not transform the columns. +@item +Creation of a table of type @code{MERGE} doesn't check if the underlaying +tables are of compatible types. @end itemize The following is known bugs in earlier versions of @strong{MySQL}: @@ -40464,6 +40543,8 @@ Allow users to change startup options. @item Subqueries. @code{select id from t where grp in (select grp from g where u > 100)} @item +Add range checking to @code{MERGE} tables. +@item Port of @strong{MySQL} to BeOS. @item Add a temporary key buffer cache during @code{insert/delete/update} so that we diff --git a/extra/perror.c b/extra/perror.c index b6d32d5086890eb38b565f3c86a0c0043ea5790c..6f2fbd864b6eb717fc531a4d2c9aa49f0e0643a1 100644 --- a/extra/perror.c +++ b/extra/perror.c @@ -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 }, }; diff --git a/include/myisammrg.h b/include/myisammrg.h index 64c2067b70f4c7360803544324da24da9debdcb3..6b1124fa180d7514349ce33714e3bff3ae385ed1 100644 --- a/include/myisammrg.h +++ b/include/myisammrg.h @@ -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, diff --git a/include/queues.h b/include/queues.h index 73907327e4ee223ec0db7be7ae9830a32bcb0dce..66125e650ca2966e73ecc57a5f06e0ed66b9ee72 100644 --- a/include/queues.h +++ b/include/queues.h @@ -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 } diff --git a/isam/isamlog.c b/isam/isamlog.c index ddeea8a267d720c13eb329ad6e79d99a5e0a0e42..d1347d46c2e6e41a7a961ea8187d70c9179ce639 100644 --- a/isam/isamlog.c +++ b/isam/isamlog.c @@ -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)))); diff --git a/myisam/mi_log.c b/myisam/mi_log.c index 9f08b835d1436fc92ce472df5b7cbf3942223d3b..d223cc69bccee30f47e033e447d7e2d225e96558 100644 --- a/myisam/mi_log.c +++ b/myisam/mi_log.c @@ -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; diff --git a/myisam/mi_open.c b/myisam/mi_open.c index 2067e3432462937d1c88c8ba4673398f0602bdf6..70096f33c5e94732386f36382af8454189f053f4 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -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: diff --git a/myisam/myisamlog.c b/myisam/myisamlog.c index c55aecfdfa684547f5e25d92c4b24249ce7f92b0..e5e8bba6ea648ea3c0e2d79a8753005cc90c1be1 100644 --- a/myisam/myisamlog.c +++ b/myisam/myisamlog.c @@ -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]++; diff --git a/myisammrg/mymrgdef.h b/myisammrg/mymrgdef.h index 945a415525f35c6a186ebed767e95814d172a1d5..564900614e2de37533f9f4172c47553d25e84891 100644 --- a/myisammrg/mymrgdef.h +++ b/myisammrg/mymrgdef.h @@ -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); diff --git a/myisammrg/myrg_create.c b/myisammrg/myrg_create.c index e5f5b988d80e8e839f3b4f37f10bc30ec64995d0..113831b9d7f232d84a93b7e0c4a16ad1fb7ec27e 100644 --- a/myisammrg/myrg_create.c +++ b/myisammrg/myrg_create.c @@ -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); diff --git a/myisammrg/myrg_open.c b/myisammrg/myrg_open.c index d3bb0b4e7b66e088c3ca957ae6944108829a2c20..c12fa1fa52b779c6f1bec3fdaa367268d612bc14 100644 --- a/myisammrg/myrg_open.c +++ b/myisammrg/myrg_open.c @@ -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); } diff --git a/myisammrg/myrg_queue.c b/myisammrg/myrg_queue.c index 4917cbf7cf87fb1e50f8a8a4ee737e53f12866fb..4d94f98472264b1d7f7df5835403557b4dc04876 100644 --- a/myisammrg/myrg_queue.c +++ b/myisammrg/myrg_queue.c @@ -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, ¬_used)); + int ret= _mi_key_cmp((MI_KEYSEG *)keyseg, aa->lastkey, bb->lastkey, + USE_WHOLE_KEY, SEARCH_FIND, ¬_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; } - diff --git a/myisammrg/myrg_rfirst.c b/myisammrg/myrg_rfirst.c index f344eb2318f200f6f2e662701ae7b95fa1f1ce45..3f29414f0762dfe8da616170e348d0d16e04853c 100644 --- a/myisammrg/myrg_rfirst.c +++ b/myisammrg/myrg_rfirst.c @@ -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; diff --git a/myisammrg/myrg_rkey.c b/myisammrg/myrg_rkey.c index c0123588a063f74ad3538aae8a3bd82775e939da..465d61ce3c68b7101b01edb8cd01bb392f616f9b 100644 --- a/myisammrg/myrg_rkey.c +++ b/myisammrg/myrg_rkey.c @@ -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 - */ - diff --git a/myisammrg/myrg_rlast.c b/myisammrg/myrg_rlast.c index ab7aacda71660127a835c15d5f74fad9e18ce9ad..f41844dfd5c1920304124ecd040acd5df8893d57 100644 --- a/myisammrg/myrg_rlast.c +++ b/myisammrg/myrg_rlast.c @@ -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; diff --git a/myisammrg/myrg_rnext.c b/myisammrg/myrg_rnext.c index e714ce3b13970e3351233d4cd45745ba07dd6946..71a4d081e8a2e94547f751c7670fb56be7cc5c7f 100644 --- a/myisammrg/myrg_rnext.c +++ b/myisammrg/myrg_rnext.c @@ -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; } - diff --git a/myisammrg/myrg_rprev.c b/myisammrg/myrg_rprev.c index 0523dc7f4e7cb81f0167c72352165a2bcbfae4d4..8d7a810696f6d6c52869f94cdf7d97a7caa9f0f8 100644 --- a/myisammrg/myrg_rprev.c +++ b/myisammrg/myrg_rprev.c @@ -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; diff --git a/myisammrg/myrg_rrnd.c b/myisammrg/myrg_rrnd.c index da11b230f2722e33db71096d4e0e7f96210e3655..c64f48c93cdf023419b349040ee468894ed0dc69 100644 --- a/myisammrg/myrg_rrnd.c +++ b/myisammrg/myrg_rrnd.c @@ -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)); } diff --git a/mysql.proj b/mysql.proj index b79381ad8c8ab25274d6f351496dee6aed321978..f8a4ea2d46f4380381d01148299e9c9b1d009760 100644 Binary files a/mysql.proj and b/mysql.proj differ diff --git a/mysys/queues.c b/mysys/queues.c index 40aa3c8db5351dceada09d817e758aa71296be49..1c7a1a4a618b12ed8eaffc4c793a482743d1a27f 100644 --- a/mysys/queues.c +++ b/mysys/queues.c @@ -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; diff --git a/sql-bench/test-insert.sh b/sql-bench/test-insert.sh index e1674f3e18dce7d35b85fbc44a4afd51ca3c7e62..427a42aea35b569c2db9bd9e6efd081508cbb4c6 100755 --- a/sql-bench/test-insert.sh +++ b/sql-bench/test-insert.sh @@ -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; diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index 591ca0bc8132138d813b7169cb3f396524b27ba2..5bdbf75749ec9795083cd06298d1c9f2dd2158a8 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -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 } diff --git a/sql/ha_heap.h b/sql/ha_heap.h index b56ee84822fe5b09fff46433910e01c38af00238..b3651a3957b91b4745eca3b5b1faa73d83804de5 100644 --- a/sql/ha_heap.h +++ b/sql/ha_heap.h @@ -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); diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h index c8f097e792fb95ab2a91c0118d44e0258e885122..e9ae9670b2fb2ca1a4dc2324fba70c752ae41914 100644 --- a/sql/ha_myisam.h +++ b/sql/ha_myisam.h @@ -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; } diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 4e6a1f195839d80bc26d16e4df15208fa9589b40..458224445279eca5004ee1a7dd741e5cc08f179a 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -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)); } diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h index 864b2f1760c875d89802d4e6976d374fe7e699d4..376c4edf18fb287d6558ac0a4b204319b006e8d3 100644 --- a/sql/ha_myisammrg.h +++ b/sql/ha_myisammrg.h @@ -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); diff --git a/sql/handler.h b/sql/handler.h index 70b05f0c7f730a20f86693af163247039a93ce93..3bf35cc88049bdb2732ab1a620217156c4c75ae0 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -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; diff --git a/sql/lex.h b/sql/lex.h index 2be54a56b1a06f8bab06da499e0524996225f77f..de4bd69fa8750494e9fe9ef39a8020727d66f6e6 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -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}, diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 3b5c87fcab25a2a8cd40d644d89f14f13ebb3798..1893046854162b8a3d43ab36906dcd1812df92b2 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -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 diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 6e1bfb23abe38d6d4ff121ddb4e056f349bd48f2..5089c8d75ee218aab3a6b90c94782ffc66893c93 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -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! diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 083bc8a83b5a00dcc8e6acf591b45d8d9de30e62..9a22d4dab04302b9cffd397beb06e7d77a29eb42 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -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; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a2ef4354521af71c8475860830f9b0ac8c41b874..97eb7c80b501e06d3120e3f0e65cd18361ae65cd 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -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); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d9d3d90f0d8e2a61d1a4894b86f6863b7d02bfb9..54569e241e07fb7564011d92cea20fe9abadfc18 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -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 diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a3da4daa9f42fb38a535222364bf25f7badf8b76..5a983c8cf063486609a8c60491dd97f9c2c88cc4 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -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) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index d4fec1289ba992e45d5b333903f3c231ca59eef4..e6952741b60649d7b399c973859c3fb2509caa1a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -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; }