Commit 9f7c4563 authored by monty@tramp.mysql.fi's avatar monty@tramp.mysql.fi

First part of automatic repair of MyISAM tables.

Error on full disk on repair.
SIGHUP signal handling.
Update with keys on timestamp
Portability fixes
parent 69a249c0
bk@work.mysql.com monty@tramp.mysql.fi
davida@work.mysql.com
jamppa@work.mysql.com
jcole@ham.spaceapes.com
jcole@jcole.burghcom.com
jcole@nslinux.bedford.progress.com
jcole@tetra.bedford.progress.com
jcole@tetra.spaceapes.com
matt@work.mysql.com
monty@donna.mysql.com
monty@work.mysql.com
mwagner@evoq.home.mwagner.org
nusphere@main.burghcom.com
paul@central.snake.net
paul@work.mysql.com
sasha@mysql.sashanet.com
sasha@work.mysql.com
serg@infomag.ape.relarn.ru
serg@work.mysql.com
sinisa@work.mysql.com
tim@localhost.polyesthetic.msg
tim@work.mysql.com
tonu@work.mysql.com
spurr@nslinux.bedford.progress.com
...@@ -8984,6 +8984,24 @@ Lock the @code{mysqld} process in memory. This works only if your system ...@@ -8984,6 +8984,24 @@ Lock the @code{mysqld} process in memory. This works only if your system
supports the @code{mlockall()} system call. This may help if you have supports the @code{mlockall()} system call. This may help if you have
a problem where the opearting system is causing @code{mysqld} to swap on disk. a problem where the opearting system is causing @code{mysqld} to swap on disk.
@item --myisam-recover [=option[,option...]]] where option is one of DEFAULT, BACKUP or FORCE.
If this option is used, @code{mysqld} will on open check if the table is
marked as crashed or if if the table wasn't closed properly
(The last option only works if you are running with @code{--skip-locking}).
If this is the case mysqld will run check on the table. If the table was
corrupted, @code{mysqld} will attempt to repair it.
The following options affects how the repair works.
@multitable @columnfractions .3 .7
@item DEFAULT @tab The same as not giving any option to @code{--myisam-recover}.
@item BACKUP @tab If the data table was changed during recover, save a backup of the @file{table_name.MYD} data file as @file{table_name-datetime.BAK}.
@item FORCE @tab Run recover even if we will loose more than one row from the .MYD file.
@end multitable
Before a table is automaticly repaired, mysqld will add a note about this
in the error log.
@item --pid-file=path @item --pid-file=path
Path to pid file used by @code{safe_mysqld}. Path to pid file used by @code{safe_mysqld}.
...@@ -21065,6 +21083,9 @@ The following is new in @code{MyISAM}: ...@@ -21065,6 +21083,9 @@ The following is new in @code{MyISAM}:
@itemize @bullet @itemize @bullet
@item @item
If @code{mysqld} is started with @code{--myisam-recover}, @code{MyISAM} tables
will automaticly be repaired on open if the table wasn't closed properly.
@item
You can @code{INSERT} new rows in a table without deleted rows, You can @code{INSERT} new rows in a table without deleted rows,
while other threads are reading from the table. while other threads are reading from the table.
@item @item
...@@ -21148,6 +21169,18 @@ Note that index files are usually much smaller with @code{MyISAM} than with ...@@ -21148,6 +21169,18 @@ Note that index files are usually much smaller with @code{MyISAM} than with
system resources than @code{ISAM}, but will need more CPU when inserting system resources than @code{ISAM}, but will need more CPU when inserting
data into compressed index. data into compressed index.
The following options to @code{mysqld} can be used to change the behavior of
@code{MyISAM} tables:
@multitable @columnfractions .40 .60
@item @strong{Option} @tab @strong{Meaning}
@item @code{--myisam-recover} @tab Automatic recover of crashed tables.
@item @code{-O myisam_sort_buffer_size=#} @tab Buffer used when recovering tables.
@item @code{--delay-key-write-for-all-tables} @tab Don't flush key buffers between writes for any MyISAM table
@end multitable
@xref{Command-line options}.
@menu @menu
* Key space:: Space needed for keys * Key space:: Space needed for keys
* MyISAM table formats:: MyISAM table formats * MyISAM table formats:: MyISAM table formats
...@@ -37416,7 +37449,14 @@ though, so 3.23 is not released as a stable version yet. ...@@ -37416,7 +37449,14 @@ though, so 3.23 is not released as a stable version yet.
@appendixsubsec Changes in release 3.23.26 @appendixsubsec Changes in release 3.23.26
@itemize @bullet @itemize @bullet
@item @item
Fixed bug in @code{FULLTEXT} index when inserting a NULL column. Automatic repair of @code{MyISAM} tables.
@item
Columns referenced in @code{INSERT} are are now properly initialized.
@item
@code{UPDATE} didn't always work when used with a range on a timestamp that
was part of the key that was used to find rows.
@item
Fixed bug in @code{FULLTEXT} index when inserting a NULL value.
@item @item
Changed to use @code{mkstemp()} instead of @code{tempnam()}. Changed to use @code{mkstemp()} instead of @code{tempnam()}.
@end itemize @end itemize
...@@ -1543,12 +1543,12 @@ com_edit(String *buffer,char *line __attribute__((unused))) ...@@ -1543,12 +1543,12 @@ com_edit(String *buffer,char *line __attribute__((unused)))
put_info("Sorry, you can't send the result to an editor in Win32", put_info("Sorry, you can't send the result to an editor in Win32",
INFO_ERROR); INFO_ERROR);
#else #else
char *filename,buff[160]; char filename[FN_REFLEN],buff[160];
int fd,tmp; int fd,tmp;
const char *editor; const char *editor;
filename = my_tempnam(NullS,"sql",MYF(MY_WME)); if ((fd=create_temp_file(filename,NullS,"sql", O_CREAT | O_WRONLY,
if ((fd = my_create(filename,0,O_CREAT | O_WRONLY, MYF(MY_WME))) < 0) MYF(MY_WME))) < 0)
goto err; goto err;
if (buffer->is_empty() && !old_buffer.is_empty()) if (buffer->is_empty() && !old_buffer.is_empty())
(void) my_write(fd,(byte*) old_buffer.ptr(),old_buffer.length(), (void) my_write(fd,(byte*) old_buffer.ptr(),old_buffer.length(),
...@@ -1576,7 +1576,6 @@ com_edit(String *buffer,char *line __attribute__((unused))) ...@@ -1576,7 +1576,6 @@ com_edit(String *buffer,char *line __attribute__((unused)))
(void) my_close(fd,MYF(0)); (void) my_close(fd,MYF(0));
(void) my_delete(filename,MYF(MY_WME)); (void) my_delete(filename,MYF(MY_WME));
err: err:
free(filename);
#endif #endif
return 0; return 0;
} }
......
...@@ -266,20 +266,21 @@ typedef struct st_dynamic_string { ...@@ -266,20 +266,21 @@ typedef struct st_dynamic_string {
typedef struct st_io_cache /* Used when cacheing files */ typedef struct st_io_cache /* Used when cacheing files */
{ {
my_off_t pos_in_file,end_of_file;
byte *rc_pos,*rc_end,*buffer,*rc_request_pos; byte *rc_pos,*rc_end,*buffer,*rc_request_pos;
int (*read_function)(struct st_io_cache *,byte *,uint);
char *file_name; /* if used with 'open_cached_file' */
char *dir,*prefix;
File file; File file;
int seek_not_done,error; int seek_not_done,error;
uint buffer_length,read_length; uint buffer_length,read_length;
my_off_t pos_in_file,end_of_file;
myf myflags; /* Flags used to my_read/my_write */ myf myflags; /* Flags used to my_read/my_write */
enum cache_type type;
#ifdef HAVE_AIOWAIT #ifdef HAVE_AIOWAIT
uint inited; uint inited;
my_off_t aio_read_pos; my_off_t aio_read_pos;
my_aio_result aio_result; my_aio_result aio_result;
#endif #endif
enum cache_type type;
int (*read_function)(struct st_io_cache *,byte *,uint);
char *file_name; /* if used with 'open_cached_file' */
} IO_CACHE; } IO_CACHE;
typedef int (*qsort2_cmp)(const void *, const void *, const void *); typedef int (*qsort2_cmp)(const void *, const void *, const void *);
...@@ -399,7 +400,7 @@ extern void TERMINATE(FILE *file); ...@@ -399,7 +400,7 @@ extern void TERMINATE(FILE *file);
#endif #endif
extern void init_glob_errs(void); extern void init_glob_errs(void);
extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags); extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags);
extern FILE *my_fdopen(File Filedes,int Flags,myf MyFlags); extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags);
extern int my_fclose(FILE *fd,myf MyFlags); extern int my_fclose(FILE *fd,myf MyFlags);
extern int my_chsize(File fd,my_off_t newlength,myf MyFlags); extern int my_chsize(File fd,my_off_t newlength,myf MyFlags);
extern int my_error _VARARGS((int nr,myf MyFlags, ...)); extern int my_error _VARARGS((int nr,myf MyFlags, ...));
...@@ -430,7 +431,7 @@ extern uint dirname_part(my_string to,const char *name); ...@@ -430,7 +431,7 @@ extern uint dirname_part(my_string to,const char *name);
extern uint dirname_length(const char *name); extern uint dirname_length(const char *name);
#define base_name(A) (A+dirname_length(A)) #define base_name(A) (A+dirname_length(A))
extern int test_if_hard_path(const char *dir_name); extern int test_if_hard_path(const char *dir_name);
extern void convert_dirname(my_string name); extern char *convert_dirname(my_string name);
extern void to_unix_path(my_string name); extern void to_unix_path(my_string name);
extern my_string fn_ext(const char *name); extern my_string fn_ext(const char *name);
extern my_string fn_same(my_string toname,const char *name,int flag); extern my_string fn_same(my_string toname,const char *name,int flag);
...@@ -507,6 +508,8 @@ extern my_bool open_cached_file(IO_CACHE *cache,const char *dir, ...@@ -507,6 +508,8 @@ extern my_bool open_cached_file(IO_CACHE *cache,const char *dir,
myf cache_myflags); myf cache_myflags);
extern my_bool real_open_cached_file(IO_CACHE *cache); extern my_bool real_open_cached_file(IO_CACHE *cache);
extern void close_cached_file(IO_CACHE *cache); extern void close_cached_file(IO_CACHE *cache);
File create_temp_file(char *to, const char *dir, const char *pfx,
int mode, myf MyFlags);
extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array,uint element_size, extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array,uint element_size,
uint init_alloc,uint alloc_increment); uint init_alloc,uint alloc_increment);
extern my_bool insert_dynamic(DYNAMIC_ARRAY *array,gptr element); extern my_bool insert_dynamic(DYNAMIC_ARRAY *array,gptr element);
......
...@@ -339,7 +339,6 @@ typedef struct st_mi_check_param ...@@ -339,7 +339,6 @@ typedef struct st_mi_check_param
typedef struct st_mi_sortinfo { typedef struct st_mi_sortinfo {
uint key_length;
ha_rows max_records; ha_rows max_records;
SORT_INFO *sort_info; SORT_INFO *sort_info;
char *tmpdir; char *tmpdir;
...@@ -347,6 +346,8 @@ typedef struct st_mi_sortinfo { ...@@ -347,6 +346,8 @@ typedef struct st_mi_sortinfo {
int (*key_read)(SORT_INFO *info,void *buff); int (*key_read)(SORT_INFO *info,void *buff);
int (*key_write)(SORT_INFO *info, const void *buff); int (*key_write)(SORT_INFO *info, const void *buff);
void (*lock_in_memory)(MI_CHECK *info); void (*lock_in_memory)(MI_CHECK *info);
uint key_length;
myf myf_rw;
} MI_SORT_PARAM; } MI_SORT_PARAM;
/* functions in mi_check */ /* functions in mi_check */
......
...@@ -1759,6 +1759,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, ...@@ -1759,6 +1759,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
sort_param.key_read=sort_key_read; sort_param.key_read=sort_key_read;
sort_param.lock_in_memory=lock_memory; sort_param.lock_in_memory=lock_memory;
sort_param.tmpdir=param->tmpdir; sort_param.tmpdir=param->tmpdir;
sort_param.myf_rw=param->myf_rw;
sort_param.sort_info=sort_info; sort_param.sort_info=sort_info;
del=info->state->del; del=info->state->del;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define MERGEBUFF2 31 #define MERGEBUFF2 31
#define MIN_SORT_MEMORY (4096-MALLOC_OVERHEAD) #define MIN_SORT_MEMORY (4096-MALLOC_OVERHEAD)
#define MYF_RW MYF(MY_NABP | MY_WME | MY_WAIT_IF_FULL) #define MYF_RW MYF(MY_NABP | MY_WME | MY_WAIT_IF_FULL)
#define DISK_BUFFER_SIZE (IO_SIZE*16)
typedef struct st_buffpek { typedef struct st_buffpek {
my_off_t file_pos; /* position to buffer */ my_off_t file_pos; /* position to buffer */
...@@ -47,30 +48,26 @@ extern void print_error _VARARGS((const char *fmt,...)); ...@@ -47,30 +48,26 @@ extern void print_error _VARARGS((const char *fmt,...));
/* functions defined in this file */ /* functions defined in this file */
static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info,uint keys, static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info,uint keys,
uchar * *sort_keys, uchar **sort_keys,
BUFFPEK *buffpek,int *maxbuffer, BUFFPEK *buffpek,int *maxbuffer,
FILE **tempfile, my_string tempname); IO_CACHE *tempfile);
static int NEAR_F write_keys(MI_SORT_PARAM *info,uchar * *sort_keys, static int NEAR_F write_keys(MI_SORT_PARAM *info,uchar * *sort_keys,
uint count, BUFFPEK *buffpek,FILE **tempfile, uint count, BUFFPEK *buffpek,IO_CACHE *tempfile);
my_string tempname);
static int NEAR_F write_index(MI_SORT_PARAM *info,uchar * *sort_keys, static int NEAR_F write_index(MI_SORT_PARAM *info,uchar * *sort_keys,
uint count); uint count);
static int NEAR_F merge_many_buff(MI_SORT_PARAM *info,uint keys, static int NEAR_F merge_many_buff(MI_SORT_PARAM *info,uint keys,
uchar * *sort_keys, uchar * *sort_keys,
BUFFPEK *buffpek,int *maxbuffer, BUFFPEK *buffpek,int *maxbuffer,
FILE * *t_file, my_string tempname); IO_CACHE *t_file);
static uint NEAR_F read_to_buffer(FILE *fromfile,BUFFPEK *buffpek, static uint NEAR_F read_to_buffer(IO_CACHE *fromfile,BUFFPEK *buffpek,
uint sort_length); uint sort_length);
static int NEAR_F merge_buffers(MI_SORT_PARAM *info,uint keys,FILE *from_file, static int NEAR_F merge_buffers(MI_SORT_PARAM *info,uint keys,
FILE *to_file, uchar * *sort_keys, IO_CACHE *from_file, IO_CACHE *to_file,
BUFFPEK *lastbuff,BUFFPEK *Fb, uchar * *sort_keys, BUFFPEK *lastbuff,
BUFFPEK *Tb); BUFFPEK *Fb, BUFFPEK *Tb);
static int NEAR_F merge_index(MI_SORT_PARAM *,uint,uchar **,BUFFPEK *, int, static int NEAR_F merge_index(MI_SORT_PARAM *,uint,uchar **,BUFFPEK *, int,
FILE *); IO_CACHE *);
static char **make_char_array(uint fields,uint length,myf my_flag); static char **make_char_array(uint fields,uint length,myf my_flag);
static FILE *opentemp(my_string name,const char *temp_dir);
static void closetemp(my_string name,FILE *stream);
/* Creates a index of sorted keys */ /* Creates a index of sorted keys */
/* Returns 0 if everything went ok */ /* Returns 0 if everything went ok */
...@@ -81,14 +78,14 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, ...@@ -81,14 +78,14 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
int error,maxbuffer,skr; int error,maxbuffer,skr;
uint memavl,old_memavl,keys,sort_length; uint memavl,old_memavl,keys,sort_length;
BUFFPEK *buffpek; BUFFPEK *buffpek;
char tempname[FN_REFLEN];
ha_rows records; ha_rows records;
uchar **sort_keys; uchar **sort_keys;
FILE *tempfile; IO_CACHE tempfile;
DBUG_ENTER("_create_index_by_sort"); DBUG_ENTER("_create_index_by_sort");
DBUG_PRINT("enter",("sort_length: %d", info->key_length)); DBUG_PRINT("enter",("sort_length: %d", info->key_length));
tempfile=0; buffpek= (BUFFPEK *) NULL; sort_keys= (uchar **) NULL; error= 1; my_b_clear(&tempfile);
buffpek= (BUFFPEK *) NULL; sort_keys= (uchar **) NULL; error= 1;
maxbuffer=1; maxbuffer=1;
memavl=max(sortbuff_size,MIN_SORT_MEMORY); memavl=max(sortbuff_size,MIN_SORT_MEMORY);
...@@ -139,8 +136,7 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, ...@@ -139,8 +136,7 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
if (!no_messages) if (!no_messages)
printf(" - Searching for keys, allocating buffer for %d keys\n",keys); printf(" - Searching for keys, allocating buffer for %d keys\n",keys);
if ((records=find_all_keys(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile, if ((records=find_all_keys(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile))
tempname))
== HA_POS_ERROR) == HA_POS_ERROR)
goto err; goto err;
if (maxbuffer == 0) if (maxbuffer == 0)
...@@ -157,13 +153,15 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, ...@@ -157,13 +153,15 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
{ {
if (!no_messages) if (!no_messages)
printf(" - Merging %lu keys\n",records); printf(" - Merging %lu keys\n",records);
if (merge_many_buff(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile, if (merge_many_buff(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile))
tempname)) goto err;
if (flush_io_cache(&tempfile) ||
reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
goto err; goto err;
} }
if (!no_messages) if (!no_messages)
puts(" - Last merge and dumping keys"); puts(" - Last merge and dumping keys");
if (merge_index(info,keys,sort_keys,buffpek,maxbuffer,tempfile)) if (merge_index(info,keys,sort_keys,buffpek,maxbuffer,&tempfile))
goto err; goto err;
} }
error =0; error =0;
...@@ -173,8 +171,7 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, ...@@ -173,8 +171,7 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
my_free((gptr) sort_keys,MYF(0)); my_free((gptr) sort_keys,MYF(0));
if (buffpek) if (buffpek)
my_free((gptr) buffpek,MYF(0)); my_free((gptr) buffpek,MYF(0));
if (tempfile) close_cached_file(&tempfile);
closetemp(tempname,tempfile);
DBUG_RETURN(error ? -1 : 0); DBUG_RETURN(error ? -1 : 0);
} /* _create_index_by_sort */ } /* _create_index_by_sort */
...@@ -184,8 +181,7 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, ...@@ -184,8 +181,7 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys, static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys,
uchar **sort_keys, BUFFPEK *buffpek, uchar **sort_keys, BUFFPEK *buffpek,
int *maxbuffer, FILE **tempfile, int *maxbuffer, IO_CACHE *tempfile)
my_string tempname)
{ {
int error; int error;
uint idx,indexpos; uint idx,indexpos;
...@@ -198,8 +194,7 @@ static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys, ...@@ -198,8 +194,7 @@ static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys,
if ((uint) ++idx == keys) if ((uint) ++idx == keys)
{ {
if (indexpos >= (uint) *maxbuffer || if (indexpos >= (uint) *maxbuffer ||
write_keys(info,sort_keys,idx-1,buffpek+indexpos,tempfile, write_keys(info,sort_keys,idx-1,buffpek+indexpos,tempfile))
tempname))
DBUG_RETURN((ha_rows) -1); DBUG_RETURN((ha_rows) -1);
memcpy(sort_keys[0],sort_keys[idx-1],(size_t) info->key_length); memcpy(sort_keys[0],sort_keys[idx-1],(size_t) info->key_length);
idx=1; indexpos++; idx=1; indexpos++;
...@@ -209,7 +204,7 @@ static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys, ...@@ -209,7 +204,7 @@ static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys,
DBUG_RETURN(HA_POS_ERROR); /* Aborted by get_key */ DBUG_RETURN(HA_POS_ERROR); /* Aborted by get_key */
if (indexpos) if (indexpos)
if (indexpos >= (uint) *maxbuffer || if (indexpos >= (uint) *maxbuffer ||
write_keys(info,sort_keys,idx,buffpek+indexpos,tempfile,tempname)) write_keys(info,sort_keys,idx,buffpek+indexpos,tempfile))
DBUG_RETURN(HA_POS_ERROR); DBUG_RETURN(HA_POS_ERROR);
*maxbuffer=(int) indexpos; *maxbuffer=(int) indexpos;
DBUG_RETURN(indexpos*(keys-1)+idx); DBUG_RETURN(indexpos*(keys-1)+idx);
...@@ -220,18 +215,23 @@ static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys, ...@@ -220,18 +215,23 @@ static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys,
static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys, static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys,
uint count, BUFFPEK *buffpek, uint count, BUFFPEK *buffpek,
register FILE **tempfile, my_string tempname) IO_CACHE *tempfile)
{ {
uchar **end;
uint sort_length=info->key_length;
DBUG_ENTER("write_keys"); DBUG_ENTER("write_keys");
qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp, qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp,
info->sort_info); info->sort_info);
if (! *tempfile && ! (*tempfile=opentemp(tempname,info->tmpdir))) if (!my_b_inited(tempfile) &&
open_cached_file(tempfile, info->tmpdir, "ST", DISK_BUFFER_SIZE,
info->myf_rw))
DBUG_RETURN(1); DBUG_RETURN(1);
buffpek->file_pos=my_ftell(*tempfile,MYF(0)); buffpek->file_pos=my_b_tell(tempfile);
buffpek->count=count; buffpek->count=count;
while (count--)
if (my_fwrite(*tempfile,(byte*)*sort_keys++,info->key_length,MYF_RW)) for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
if (my_b_write(tempfile,(byte*) *sort_keys,(uint) sort_length))
DBUG_RETURN(1); DBUG_RETURN(1);
DBUG_RETURN(0); DBUG_RETURN(0);
} /* write_keys */ } /* write_keys */
...@@ -239,7 +239,8 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys, ...@@ -239,7 +239,8 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys,
/* Write index */ /* Write index */
static int NEAR_F write_index(MI_SORT_PARAM *info, register uchar **sort_keys, register uint count) static int NEAR_F write_index(MI_SORT_PARAM *info, register uchar **sort_keys,
register uint count)
{ {
DBUG_ENTER("write_index"); DBUG_ENTER("write_index");
...@@ -256,22 +257,25 @@ static int NEAR_F write_index(MI_SORT_PARAM *info, register uchar **sort_keys, r ...@@ -256,22 +257,25 @@ static int NEAR_F write_index(MI_SORT_PARAM *info, register uchar **sort_keys, r
static int NEAR_F merge_many_buff(MI_SORT_PARAM *info, uint keys, static int NEAR_F merge_many_buff(MI_SORT_PARAM *info, uint keys,
uchar **sort_keys, BUFFPEK *buffpek, uchar **sort_keys, BUFFPEK *buffpek,
int *maxbuffer, FILE **t_file, int *maxbuffer, IO_CACHE *t_file)
my_string t_name)
{ {
register int i; register int i;
FILE *from_file,*to_file,*temp; IO_CACHE t_file2, *from_file, *to_file, *temp;
FILE *t_file2;
char t_name2[FN_REFLEN];
BUFFPEK *lastbuff; BUFFPEK *lastbuff;
DBUG_ENTER("merge_many_buff"); DBUG_ENTER("merge_many_buff");
if (!(t_file2=opentemp(t_name2,info->tmpdir))) if (*maxbuffer < MERGEBUFF2)
DBUG_RETURN(1); DBUG_RETURN(0); /* purecov: inspected */
if (flush_io_cache(t_file) ||
open_cached_file(&t_file2,info->tmpdir,"ST",DISK_BUFFER_SIZE,
info->myf_rw))
DBUG_RETURN(1); /* purecov: inspected */
from_file= *t_file ; to_file= t_file2; from_file= t_file ; to_file= &t_file2;
while (*maxbuffer >= MERGEBUFF2) while (*maxbuffer >= MERGEBUFF2)
{ {
reinit_io_cache(from_file,READ_CACHE,0L,0,0);
reinit_io_cache(to_file,WRITE_CACHE,0L,0,0);
lastbuff=buffpek; lastbuff=buffpek;
for (i=0 ; i <= *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF) for (i=0 ; i <= *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
{ {
...@@ -282,17 +286,14 @@ static int NEAR_F merge_many_buff(MI_SORT_PARAM *info, uint keys, ...@@ -282,17 +286,14 @@ static int NEAR_F merge_many_buff(MI_SORT_PARAM *info, uint keys,
if (merge_buffers(info,keys,from_file,to_file,sort_keys,lastbuff++, if (merge_buffers(info,keys,from_file,to_file,sort_keys,lastbuff++,
buffpek+i,buffpek+ *maxbuffer)) buffpek+i,buffpek+ *maxbuffer))
break; break;
*maxbuffer= (int) (lastbuff-buffpek)-1; if (flush_io_cache(to_file))
break; /* purecov: inspected */
temp=from_file; from_file=to_file; to_file=temp; temp=from_file; from_file=to_file; to_file=temp;
VOID(my_fseek(to_file,0L,MY_SEEK_SET,MYF(0))); *maxbuffer= (int) (lastbuff-buffpek)-1;
}
if (to_file == *t_file)
{
closetemp(t_name,to_file);
*t_file=t_file2;
VOID(strmov(t_name,t_name2));
} }
else closetemp(t_name2,to_file); close_cached_file(to_file); // This holds old result
if (to_file == t_file)
*t_file=t_file2; // Copy result file
DBUG_RETURN(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */ DBUG_RETURN(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */
} /* merge_many_buff */ } /* merge_many_buff */
...@@ -301,20 +302,17 @@ static int NEAR_F merge_many_buff(MI_SORT_PARAM *info, uint keys, ...@@ -301,20 +302,17 @@ static int NEAR_F merge_many_buff(MI_SORT_PARAM *info, uint keys,
/* Read data to buffer */ /* Read data to buffer */
/* This returns (uint) -1 if something goes wrong */ /* This returns (uint) -1 if something goes wrong */
static uint NEAR_F read_to_buffer(FILE *fromfile, BUFFPEK *buffpek, uint sort_length) static uint NEAR_F read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
uint sort_length)
{ {
register uint count; register uint count;
uint length; uint length;
count=buffpek->max_keys; if ((count=(uint) min((ha_rows) buffpek->max_keys,buffpek->count)))
if ((ha_rows) count > buffpek->count)
count=(uint) buffpek->count;
if (count)
{ {
VOID(my_fseek(fromfile,buffpek->file_pos,MY_SEEK_SET,MYF(0))); if (my_pread(fromfile->file,(byte*) buffpek->base,
if (my_fread(fromfile,(byte*) buffpek->base, (length= sort_length*count),buffpek->file_pos,MYF_RW))
(length= sort_length*count),MYF_RW)) return((uint) -1); /* purecov: inspected */
return((uint) -1);
buffpek->key=buffpek->base; buffpek->key=buffpek->base;
buffpek->file_pos+= length; /* New filepos */ buffpek->file_pos+= length; /* New filepos */
buffpek->count-= count; buffpek->count-= count;
...@@ -328,8 +326,9 @@ static uint NEAR_F read_to_buffer(FILE *fromfile, BUFFPEK *buffpek, uint sort_le ...@@ -328,8 +326,9 @@ static uint NEAR_F read_to_buffer(FILE *fromfile, BUFFPEK *buffpek, uint sort_le
/* If to_file == 0 then use info->key_write */ /* If to_file == 0 then use info->key_write */
static int NEAR_F static int NEAR_F
merge_buffers(MI_SORT_PARAM *info, uint keys, FILE *from_file, FILE *to_file, merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
uchar **sort_keys, BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb) IO_CACHE *to_file, uchar **sort_keys, BUFFPEK *lastbuff,
BUFFPEK *Fb, BUFFPEK *Tb)
{ {
int error; int error;
uint sort_length,maxcount; uint sort_length,maxcount;
...@@ -342,12 +341,11 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, FILE *from_file, FILE *to_file, ...@@ -342,12 +341,11 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, FILE *from_file, FILE *to_file,
count=error=0; count=error=0;
maxcount=keys/((uint) (Tb-Fb) +1); maxcount=keys/((uint) (Tb-Fb) +1);
sort_length=info->key_length;
LINT_INIT(to_start_filepos); LINT_INIT(to_start_filepos);
if (to_file) if (to_file)
to_start_filepos=my_ftell(to_file,MYF(0)); to_start_filepos=my_b_tell(to_file);
strpos=(uchar*) sort_keys; strpos=(uchar*) sort_keys;
sort_length=info->key_length;
if (init_queue(&queue,(uint) (Tb-Fb)+1,offsetof(BUFFPEK,key),0, if (init_queue(&queue,(uint) (Tb-Fb)+1,offsetof(BUFFPEK,key),0,
(int (*)(void*, byte *,byte*)) info->key_cmp, (int (*)(void*, byte *,byte*)) info->key_cmp,
...@@ -373,8 +371,7 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, FILE *from_file, FILE *to_file, ...@@ -373,8 +371,7 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, FILE *from_file, FILE *to_file,
buffpek=(BUFFPEK*) queue_top(&queue); buffpek=(BUFFPEK*) queue_top(&queue);
if (to_file) if (to_file)
{ {
if (my_fwrite(to_file,(byte*) buffpek->key,(uint) sort_length, if (my_b_write(to_file,(byte*) buffpek->key,(uint) sort_length))
MYF_RW | MY_WAIT_IF_FULL))
{ {
error=1; goto err; error=1; goto err;
} }
...@@ -417,6 +414,8 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, FILE *from_file, FILE *to_file, ...@@ -417,6 +414,8 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, FILE *from_file, FILE *to_file,
break; /* One buffer have been removed */ break; /* One buffer have been removed */
} }
} }
else if (error == -1)
goto err; /* purecov: inspected */
queue_replaced(&queue); /* Top element has been replaced */ queue_replaced(&queue); /* Top element has been replaced */
} }
} }
...@@ -427,9 +426,8 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, FILE *from_file, FILE *to_file, ...@@ -427,9 +426,8 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, FILE *from_file, FILE *to_file,
{ {
if (to_file) if (to_file)
{ {
if (my_fwrite(to_file,(byte*) buffpek->key, if (my_b_write(to_file,(byte*) buffpek->key,
(uint) (sort_length*buffpek->mem_count), (sort_length*buffpek->mem_count)))
MYF_RW | MY_WAIT_IF_FULL))
{ {
error=1; goto err; error=1; goto err;
} }
...@@ -454,7 +452,7 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, FILE *from_file, FILE *to_file, ...@@ -454,7 +452,7 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, FILE *from_file, FILE *to_file,
lastbuff->count=count; lastbuff->count=count;
if (to_file) if (to_file)
lastbuff->file_pos=to_start_filepos; /* New block starts here */ lastbuff->file_pos=to_start_filepos;
err: err:
delete_queue(&queue); delete_queue(&queue);
DBUG_RETURN(error); DBUG_RETURN(error);
...@@ -465,10 +463,10 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, FILE *from_file, FILE *to_file, ...@@ -465,10 +463,10 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, FILE *from_file, FILE *to_file,
static int NEAR_F static int NEAR_F
merge_index(MI_SORT_PARAM *info, uint keys, uchar **sort_keys, merge_index(MI_SORT_PARAM *info, uint keys, uchar **sort_keys,
BUFFPEK *buffpek, int maxbuffer, FILE *tempfile) BUFFPEK *buffpek, int maxbuffer, IO_CACHE *tempfile)
{ {
DBUG_ENTER("merge_index"); DBUG_ENTER("merge_index");
if (merge_buffers(info,keys,tempfile,(FILE*) 0,sort_keys,buffpek,buffpek, if (merge_buffers(info,keys,tempfile,(IO_CACHE*) 0,sort_keys,buffpek,buffpek,
buffpek+maxbuffer)) buffpek+maxbuffer))
DBUG_RETURN(1); DBUG_RETURN(1);
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -492,40 +490,3 @@ static char **make_char_array(register uint fields, uint length, myf my_flag) ...@@ -492,40 +490,3 @@ static char **make_char_array(register uint fields, uint length, myf my_flag)
DBUG_RETURN(old_pos); DBUG_RETURN(old_pos);
} /* make_char_array */ } /* make_char_array */
/* Open a temporary file that will be deleted on close */
static FILE *opentemp(my_string name,const char *temp_dir)
{
FILE *stream;
reg1 my_string str_pos;
DBUG_ENTER("opentemp");
if (!(str_pos=my_tempnam(temp_dir,"ST",MYF(MY_WME))))
DBUG_RETURN(0);
VOID(strmov(name,str_pos));
(*free)(str_pos); /* Avoid the 'free' macro */
stream=my_fopen(name,(int) (O_RDWR | FILE_BINARY | O_CREAT | O_TEMPORARY),
MYF(MY_WME));
#if O_TEMPORARY == 0 && !defined(CANT_DELETE_OPEN_FILES)
VOID(my_delete(name,MYF(MY_WME | ME_NOINPUT)));
#endif
DBUG_PRINT("exit",("stream: %lx",stream));
DBUG_RETURN (stream);
} /* opentemp */
static void closetemp(my_string name __attribute__((unused)), FILE *stream)
{
DBUG_ENTER("closetemp");
if (stream)
VOID(my_fclose(stream,MYF(MY_WME)));
#if !(O_TEMPORARY == 0 && !defined(CANT_DELETE_OPEN_FILES))
if (name)
VOID(my_delete(name,MYF(MY_WME)));
#endif
DBUG_VOID_RETURN;
} /* closetemp */
...@@ -18,66 +18,115 @@ ...@@ -18,66 +18,115 @@
/* Open a temporary file and cache it with io_cache. Delete it on close */ /* Open a temporary file and cache it with io_cache. Delete it on close */
#include "mysys_priv.h" #include "mysys_priv.h"
#include <m_string.h>
#include "my_static.h"
#include "mysys_err.h"
#include <paths.h>
#define TMP_EXT ".tmp" /* Extension of tempfile */
#if ! defined(P_tmpdir)
#define P_tmpdir ""
#endif
#ifdef HAVE_TEMPNAM
#ifndef MSDOS
extern char **environ;
#endif
#endif
/*
Remove an open tempfile so that it doesn't survive
if we crash; If the operating system doesn't support
this, just remember the file name for later removal
*/
static my_bool cache_remove_open_tmp(IO_CACHE *cache, const char *name)
{
#if O_TEMPORARY == 0
#if !defined(CANT_DELETE_OPEN_FILES)
/* The following should always succeed */
(void) my_delete(name,MYF(MY_WME | ME_NOINPUT));
#else
int length;
if (!(cache->file_name=
(char*) my_malloc((length=strlen(name)+1),MYF(MY_WME)))
{
my_close(cache->file,MYF(0));
cache->file = -1;
errno=my_error=ENOMEM;
return 1;
}
memcpy(cache->file_name,name,length);
#endif
#endif /* O_TEMPORARY == 0 */
return 0;
}
/* /*
** Open a cached tempfile by IO_CACHE ** Open tempfile cached by IO_CACHE
** Should be used when no seeks are done (only reinit_io_buff) ** Should be used when no seeks are done (only reinit_io_buff)
** Return 0 if cache is inited ok ** Return 0 if cache is inited ok
** The actual file is created when the IO_CACHE buffer gets filled ** The actual file is created when the IO_CACHE buffer gets filled
** If dir is not given, use TMPDIR.
*/ */
my_bool open_cached_file(IO_CACHE *cache, const char* dir, const char *prefix, my_bool open_cached_file(IO_CACHE *cache, const char* dir, const char *prefix,
uint cache_size, myf cache_myflags) uint cache_size, myf cache_myflags)
{ {
DBUG_ENTER("open_cached_file"); DBUG_ENTER("open_cached_file");
cache->dir= dir ? my_strdup(dir,MYF(cache_myflags & MY_WME)) : (char*) 0;
cache->prefix= (prefix ? my_strdup(prefix,MYF(cache_myflags & MY_WME)) :
(char*) 0);
cache->file_name=0;
cache->buffer=0; /* Mark that not open */ cache->buffer=0; /* Mark that not open */
if (!(cache->file_name=my_tempnam(dir,prefix,MYF(MY_WME))))
DBUG_RETURN(1);
if (!init_io_cache(cache,-1,cache_size,WRITE_CACHE,0L,0, if (!init_io_cache(cache,-1,cache_size,WRITE_CACHE,0L,0,
MYF(cache_myflags | MY_NABP))) MYF(cache_myflags | MY_NABP)))
{ {
DBUG_RETURN(0); DBUG_RETURN(0);
} }
(*free)(cache->file_name); /* my_tempnam uses malloc() */ my_free(cache->dir, MYF(MY_ALLOW_ZERO_PTR));
cache->file_name=0; my_free(cache->prefix,MYF(MY_ALLOW_ZERO_PTR));
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/* Create the temporary file */
my_bool real_open_cached_file(IO_CACHE *cache) my_bool real_open_cached_file(IO_CACHE *cache)
{ {
char name_buff[FN_REFLEN];
int error=1;
DBUG_ENTER("real_open_cached_file"); DBUG_ENTER("real_open_cached_file");
if ((cache->file=my_create(cache->file_name,0, if ((cache->file=create_temp_file(name_buff, cache->dir, cache->prefix,
(int) (O_RDWR | O_BINARY | O_TRUNC | O_TEMPORARY | (O_RDWR | O_BINARY | O_TRUNC |
O_SHORT_LIVED), O_TEMPORARY | O_SHORT_LIVED),
MYF(MY_WME))) >= 0) MYF(MY_WME))) >= 0)
{ {
#if O_TEMPORARY == 0 && !defined(CANT_DELETE_OPEN_FILES) error=0;
VOID(my_delete(cache->file_name,MYF(MY_WME | ME_NOINPUT))); cache_remove_open_tmp(cache, name_buff);
#endif
DBUG_RETURN(0);
} }
DBUG_RETURN(1); DBUG_RETURN(error);
} }
void close_cached_file(IO_CACHE *cache) void close_cached_file(IO_CACHE *cache)
{ {
DBUG_ENTER("close_cached_file"); DBUG_ENTER("close_cached_file");
if (my_b_inited(cache)) if (my_b_inited(cache))
{ {
VOID(end_io_cache(cache)); (void) end_io_cache(cache);
if (cache->file >= 0) if (cache->file >= 0)
{ {
VOID(my_close(cache->file,MYF(MY_WME))); (void) my_close(cache->file,MYF(0));
#ifdef CANT_DELETE_OPEN_FILES #ifdef CANT_DELETE_OPEN_FILES
VOID(my_delete(cache->file_name,MYF(MY_WME | ME_NOINPUT))); if (cache->file_name)
{
(void) my_delete(cache->file_name,MYF(MY_WME | ME_NOINPUT));
my_free(cache->file_name,MYF(0));
}
#endif #endif
} }
if (cache->file_name) my_free(cache->dir,MYF(MY_ALLOW_ZERO_PTR));
(*free)(cache->file_name); /* my_tempnam uses malloc() */ my_free(cache->prefix,MYF(MY_ALLOW_ZERO_PTR));
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -66,8 +66,9 @@ uint dirname_part(my_string to, const char *name) ...@@ -66,8 +66,9 @@ uint dirname_part(my_string to, const char *name)
#define FN_DEVCHAR '\0' /* For easier code */ #define FN_DEVCHAR '\0' /* For easier code */
#endif #endif
void convert_dirname(my_string to) char *convert_dirname(my_string to)
{ {
reg1 char *pos;
#ifdef FN_UPPER_CASE #ifdef FN_UPPER_CASE
caseup_str(to); caseup_str(to);
#endif #endif
...@@ -76,7 +77,6 @@ void convert_dirname(my_string to) ...@@ -76,7 +77,6 @@ void convert_dirname(my_string to)
#endif #endif
#if FN_LIBCHAR != '/' #if FN_LIBCHAR != '/'
{ {
reg1 my_string pos;
pos=to-1; /* Change from '/' */ pos=to-1; /* Change from '/' */
while ((pos=strchr(pos+1,'/')) != 0) while ((pos=strchr(pos+1,'/')) != 0)
*pos=FN_LIBCHAR; *pos=FN_LIBCHAR;
...@@ -84,7 +84,6 @@ void convert_dirname(my_string to) ...@@ -84,7 +84,6 @@ void convert_dirname(my_string to)
#endif #endif
#ifdef FN_C_BEFORE_DIR_2 #ifdef FN_C_BEFORE_DIR_2
{ {
reg1 my_string pos;
for (pos=to ; *pos ; pos++) for (pos=to ; *pos ; pos++)
{ {
if (*pos == FN_C_BEFORE_DIR_2) if (*pos == FN_C_BEFORE_DIR_2)
...@@ -95,12 +94,13 @@ void convert_dirname(my_string to) ...@@ -95,12 +94,13 @@ void convert_dirname(my_string to)
} }
#else #else
{ /* Append FN_LIBCHAR if not there */ { /* Append FN_LIBCHAR if not there */
char *end=strend(to); pos=strend(to);
if (end != to && (end[-1] != FN_LIBCHAR && end[-1] != FN_DEVCHAR)) if (pos != to && (pos[-1] != FN_LIBCHAR && pos[-1] != FN_DEVCHAR))
{ {
end[0]=FN_LIBCHAR; *pos++=FN_LIBCHAR;
end[1]=0; *pos=0;
} }
} }
#endif #endif
return pos; /* Pointer to end of dir */
} /* convert_dirname */ } /* convert_dirname */
...@@ -95,7 +95,7 @@ int my_fclose(FILE *fd, myf MyFlags) ...@@ -95,7 +95,7 @@ int my_fclose(FILE *fd, myf MyFlags)
if ((uint) file < MY_NFILE && my_file_info[file].type != UNOPEN) if ((uint) file < MY_NFILE && my_file_info[file].type != UNOPEN)
{ {
my_file_info[file].type = UNOPEN; my_file_info[file].type = UNOPEN;
my_free(my_file_info[file].name, MYF(0)); my_free(my_file_info[file].name, MYF(MY_ALLOW_ZERO_PTR));
} }
pthread_mutex_unlock(&THR_LOCK_open); pthread_mutex_unlock(&THR_LOCK_open);
DBUG_RETURN(err); DBUG_RETURN(err);
...@@ -103,11 +103,9 @@ int my_fclose(FILE *fd, myf MyFlags) ...@@ -103,11 +103,9 @@ int my_fclose(FILE *fd, myf MyFlags)
/* Make a stream out of a file handle */ /* Make a stream out of a file handle */
/* Name may be 0 */
FILE *my_fdopen(File Filedes, int Flags, myf MyFlags) FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags)
/* Read | write .. */
/* Special flags */
{ {
FILE *fd; FILE *fd;
char type[5]; char type[5];
...@@ -125,11 +123,18 @@ FILE *my_fdopen(File Filedes, int Flags, myf MyFlags) ...@@ -125,11 +123,18 @@ FILE *my_fdopen(File Filedes, int Flags, myf MyFlags)
else else
{ {
pthread_mutex_lock(&THR_LOCK_open); pthread_mutex_lock(&THR_LOCK_open);
my_stream_opened++;
if (Filedes < MY_NFILE)
{
if (my_file_info[Filedes].type != UNOPEN) if (my_file_info[Filedes].type != UNOPEN)
{ {
my_file_info[Filedes].type = STREAM_BY_FDOPEN;
my_file_opened--; /* File is opened with my_open ! */ my_file_opened--; /* File is opened with my_open ! */
my_stream_opened++; }
else
{
my_file_info[Filedes].name= my_strdup(name,MyFlags);
}
my_file_info[Filedes].type = STREAM_BY_FDOPEN;
} }
pthread_mutex_unlock(&THR_LOCK_open); pthread_mutex_unlock(&THR_LOCK_open);
} }
......
...@@ -351,7 +351,7 @@ rl_translate_keyseq (seq, array, len) ...@@ -351,7 +351,7 @@ rl_translate_keyseq (seq, array, len)
{ {
register int i, c, l, temp; register int i, c, l, temp;
for (i = l = 0; c = seq[i]; i++) for (i = l = 0; (c = seq[i]); i++)
{ {
if (c == '\\') if (c == '\\')
{ {
...@@ -1028,7 +1028,7 @@ rl_parse_and_bind (string) ...@@ -1028,7 +1028,7 @@ rl_parse_and_bind (string)
{ {
int passc = 0; int passc = 0;
for (i = 1; c = string[i]; i++) for (i = 1; (c = string[i]); i++)
{ {
if (passc) if (passc)
{ {
...@@ -1104,7 +1104,7 @@ rl_parse_and_bind (string) ...@@ -1104,7 +1104,7 @@ rl_parse_and_bind (string)
{ {
int delimiter = string[i++], passc; int delimiter = string[i++], passc;
for (passc = 0; c = string[i]; i++) for (passc = 0; (c = string[i]); i++)
{ {
if (passc) if (passc)
{ {
...@@ -1721,7 +1721,7 @@ rl_function_dumper (print_readably) ...@@ -1721,7 +1721,7 @@ rl_function_dumper (print_readably)
fprintf (rl_outstream, "\n"); fprintf (rl_outstream, "\n");
for (i = 0; name = names[i]; i++) for (i = 0; (name = names[i]); i++)
{ {
Function *function; Function *function;
char **invokers; char **invokers;
......
...@@ -1377,7 +1377,7 @@ completion_matches (text, entry_function) ...@@ -1377,7 +1377,7 @@ completion_matches (text, entry_function)
match_list = (char **)xmalloc ((match_list_size + 1) * sizeof (char *)); match_list = (char **)xmalloc ((match_list_size + 1) * sizeof (char *));
match_list[1] = (char *)NULL; match_list[1] = (char *)NULL;
while (string = (*entry_function) (text, matches)) while ((string = (*entry_function) (text, matches)))
{ {
if (matches + 1 == match_list_size) if (matches + 1 == match_list_size)
match_list = (char **)xrealloc match_list = (char **)xrealloc
...@@ -1427,7 +1427,7 @@ username_completion_function (text, state) ...@@ -1427,7 +1427,7 @@ username_completion_function (text, state)
setpwent (); setpwent ();
} }
while (entry = getpwent ()) while ((entry = getpwent ()))
{ {
/* Null usernames should result in all users as possible completions. */ /* Null usernames should result in all users as possible completions. */
if (namelen == 0 || (STREQN (username, entry->pw_name, namelen))) if (namelen == 0 || (STREQN (username, entry->pw_name, namelen)))
......
...@@ -200,7 +200,7 @@ get_history_event (string, caller_index, delimiting_quote) ...@@ -200,7 +200,7 @@ get_history_event (string, caller_index, delimiting_quote)
} }
/* Only a closing `?' or a newline delimit a substring search string. */ /* Only a closing `?' or a newline delimit a substring search string. */
for (local_index = i; c = string[i]; i++) for (local_index = i; (c = string[i]); i++)
if ((!substring_okay && (whitespace (c) || c == ':' || if ((!substring_okay && (whitespace (c) || c == ':' ||
(history_search_delimiter_chars && member (c, history_search_delimiter_chars)) || (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
string[i] == delimiting_quote)) || string[i] == delimiting_quote)) ||
......
...@@ -368,7 +368,7 @@ rl_read_key () ...@@ -368,7 +368,7 @@ rl_read_key ()
else else
{ {
/* If input is coming from a macro, then use that. */ /* If input is coming from a macro, then use that. */
if (c = _rl_next_macro_key ()) if ((c = _rl_next_macro_key ()))
return (c); return (c);
/* If the user has an event function, then call it periodically. */ /* If the user has an event function, then call it periodically. */
......
...@@ -174,7 +174,7 @@ noninc_search (dir, pchar) ...@@ -174,7 +174,7 @@ noninc_search (dir, pchar)
#define SEARCH_RETURN rl_restore_prompt (); return #define SEARCH_RETURN rl_restore_prompt (); return
/* Read the search string. */ /* Read the search string. */
while (c = rl_read_key ()) while ((c = rl_read_key ()))
{ {
switch (c) switch (c)
{ {
......
...@@ -38,6 +38,10 @@ ...@@ -38,6 +38,10 @@
# include "ansi_stdlib.h" # include "ansi_stdlib.h"
#endif /* HAVE_STDLIB_H */ #endif /* HAVE_STDLIB_H */
#if defined (HAVE_STDIO_H)
# include <stdio.h>
#endif /* HAVE_STDIO_H */
#if defined (HAVE_STRING_H) #if defined (HAVE_STRING_H)
# include <string.h> # include <string.h>
#else #else
......
...@@ -232,6 +232,8 @@ _rl_set_screen_size (rows, cols) ...@@ -232,6 +232,8 @@ _rl_set_screen_size (rows, cols)
screenchars = screenwidth * screenheight; screenchars = screenwidth * screenheight;
} }
extern void _rl_redisplay_after_sigwinch();
void void
rl_resize_terminal () rl_resize_terminal ()
{ {
...@@ -251,32 +253,32 @@ struct _tc_string { ...@@ -251,32 +253,32 @@ struct _tc_string {
search algorithm to something smarter. */ search algorithm to something smarter. */
static struct _tc_string tc_strings[] = static struct _tc_string tc_strings[] =
{ {
"DC", &term_DC, {"DC", &term_DC},
"IC", &term_IC, {"IC", &term_IC},
"ce", &term_clreol, {"ce", &term_clreol},
"cl", &term_clrpag, {"cl", &term_clrpag},
"cr", &term_cr, {"cr", &term_cr},
"dc", &term_dc, {"dc", &term_dc},
"ei", &term_ei, {"ei", &term_ei},
"ic", &term_ic, {"ic", &term_ic},
"im", &term_im, {"im", &term_im},
"kd", &term_kd, {"kd", &term_kd},
"kh", &term_kh, /* home */ {"kh", &term_kh}, /* home */
"kH", &term_kH, /* end */ {"kH", &term_kH}, /* end */
"kl", &term_kl, {"kl", &term_kl},
"kr", &term_kr, {"kr", &term_kr},
"ku", &term_ku, {"ku", &term_ku},
"ks", &term_ks, {"ks", &term_ks},
"ke", &term_ke, {"ke", &term_ke},
"le", &term_backspace, {"le", &term_backspace},
"mm", &term_mm, {"mm", &term_mm},
"mo", &term_mo, {"mo", &term_mo},
#if defined (HACK_TERMCAP_MOTION) #if defined (HACK_TERMCAP_MOTION)
"nd", &term_forward_char, {"nd", &term_forward_char},
#endif #endif
"pc", &term_pc, {"pc", &term_pc},
"up", &term_up, {"up", &term_up},
"vb", &visible_bell, {"vb", &visible_bell},
}; };
#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string)) #define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
......
...@@ -182,7 +182,7 @@ tilde_expand (string) ...@@ -182,7 +182,7 @@ tilde_expand (string)
int result_size, result_index; int result_size, result_index;
result_index = result_size = 0; result_index = result_size = 0;
if (result = strchr (string, '~')) if ((result = strchr (string, '~')))
result = xmalloc (result_size = (strlen (string) + 16)); result = xmalloc (result_size = (strlen (string) + 16));
else else
result = xmalloc (result_size = (strlen (string) + 1)); result = xmalloc (result_size = (strlen (string) + 1));
......
...@@ -106,7 +106,7 @@ rl_do_undo () ...@@ -106,7 +106,7 @@ rl_do_undo ()
{ {
UNDO_LIST *release; UNDO_LIST *release;
int waiting_for_begin = 0; int waiting_for_begin = 0;
int start, end; int start = 0, end = 0;
#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i))) #define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
......
...@@ -3,100 +3,102 @@ static struct cname { ...@@ -3,100 +3,102 @@ static struct cname {
char *name; char *name;
char code; char code;
} cnames[] = { } cnames[] = {
"NUL", '\0', {"NUL", '\0'},
"SOH", '\001', {"SOH", '\001'},
"STX", '\002', {"STX", '\002'},
"ETX", '\003', {"ETX", '\003'},
"EOT", '\004', {"EOT", '\004'},
"ENQ", '\005', {"ENQ", '\005'},
"ACK", '\006', {"ACK", '\006'},
"BEL", '\007', {"BEL", '\007'},
"alert", '\007', {"alert", '\007'},
"BS", '\010', {"BS", '\010'},
"backspace", '\b', {"backspace", '\b'},
"HT", '\011', {"HT", '\011'},
"tab", '\t', {"tab", '\t'},
"LF", '\012', {"LF", '\012'},
"newline", '\n', {"newline", '\n'},
"VT", '\013', {"VT", '\013'},
"vertical-tab", '\v', {"vertical-tab",'\v'},
"FF", '\014', {"FF", '\014'},
"form-feed", '\f', {"form-feed", '\f'},
"CR", '\015', {"CR", '\015'},
"carriage-return", '\r', {"carriage-return", '\r'},
"SO", '\016', {"SO", '\016'},
"SI", '\017', {"SI", '\017'},
"DLE", '\020', {"DLE", '\020'},
"DC1", '\021', {"DC1", '\021'},
"DC2", '\022', {"DC2", '\022'},
"DC3", '\023', {"DC3", '\023'},
"DC4", '\024', {"DC4", '\024'},
"NAK", '\025', {"NAK", '\025'},
"SYN", '\026', {"SYN", '\026'},
"ETB", '\027', {"ETB", '\027'},
"CAN", '\030', {"CAN", '\030'},
"EM", '\031', {"EM", '\031'},
"SUB", '\032', {"SUB", '\032'},
"ESC", '\033', {"ESC", '\033'},
"IS4", '\034', {"IS4", '\034'},
"FS", '\034', {"FS", '\034'},
"IS3", '\035', {"IS3", '\035'},
"GS", '\035', {"GS", '\035'},
"IS2", '\036', {"IS2", '\036'},
"RS", '\036', {"RS", '\036'},
"IS1", '\037', {"IS1", '\037'},
"US", '\037', {"US", '\037'},
"space", ' ', {"space", ' '},
"exclamation-mark", '!', {"exclamation-mark", '!'},
"quotation-mark", '"', {"quotation-mark", '"'},
"number-sign", '#', {"number-sign", '#'},
"dollar-sign", '$', {"dollar-sign", '$'},
"percent-sign", '%', {"percent-sign", '%'},
"ampersand", '&', {"ampersand", '&'},
"apostrophe", '\'', {"apostrophe", '\''},
"left-parenthesis", '(', {"left-parenthesis", '('},
"right-parenthesis", ')', {"right-parenthesis", ')'},
"asterisk", '*', {"asterisk", '*'},
"plus-sign", '+', {"plus-sign", '+'},
"comma", ',', {"comma", ','},
"hyphen", '-', {"hyphen", '-'},
"hyphen-minus", '-', {"hyphen-minus", '-'},
"period", '.', {"period", '.'},
"full-stop", '.', {"full-stop", '.'},
"slash", '/', {"slash", '/'},
"solidus", '/', {"solidus", '/'},
"zero", '0', {"zero", '0'},
"one", '1', {"one", '1'},
"two", '2', {"two", '2'},
"three", '3', {"three", '3'},
"four", '4', {"four", '4'},
"five", '5', {"five", '5'},
"six", '6', {"six", '6'},
"seven", '7', {"seven", '7'},
"eight", '8', {"eight", '8'},
"nine", '9', {"nine", '9'},
"colon", ':', {"colon", ':'},
"semicolon", ';', {"semicolon", ';'},
"less-than-sign", '<', {"less-than-sign", '<'},
"equals-sign", '=', {"equals-sign", '='},
"greater-than-sign", '>', {"greater-than-sign", '>'},
"question-mark", '?', {"question-mark", '?'},
"commercial-at", '@', {"commercial-at", '@'},
"left-square-bracket", '[', {"left-square-bracket", '['},
"backslash", '\\', {"backslash", '\\'},
"reverse-solidus", '\\', {"reverse-solidus", '\\'},
"right-square-bracket", ']', {"right-square-bracket",']'},
"circumflex", '^', {"circumflex", '^'},
"circumflex-accent", '^', {"circumflex-accent", '^'},
"underscore", '_', {"underscore", '_'},
"low-line", '_', {"low-line", '_'},
"grave-accent", '`', {"grave-accent", '`'},
"left-brace", '{', {"left-brace", '{'},
"left-curly-bracket", '{', {"left-curly-bracket", '{'},
"vertical-line", '|', {"vertical-line", '|'},
"right-brace", '}', {"right-brace", '}'},
"right-curly-bracket", '}', {"right-curly-bracket", '}'},
"tilde", '~', {"tilde", '~'},
"DEL", '\177', {"DEL", '\177'},
NULL, 0, {NULL, 0},
}; };
...@@ -217,7 +217,7 @@ FILE *d; ...@@ -217,7 +217,7 @@ FILE *d;
fprintf(d, ">"); fprintf(d, ">");
break; break;
default: default:
fprintf(d, "!%d(%d)!", OP(*s), opnd); fprintf(d, "!%ld(%ld)!", OP(*s), opnd);
break; break;
} }
if (!done) if (!done)
......
...@@ -103,7 +103,7 @@ char *argv[]; ...@@ -103,7 +103,7 @@ char *argv[];
len = (int)(subs[0].rm_eo - subs[0].rm_so); len = (int)(subs[0].rm_eo - subs[0].rm_so);
if (subs[0].rm_so != -1) { if (subs[0].rm_so != -1) {
if (len != 0) if (len != 0)
printf("match `%.*s'\n", len, printf("match `%.*s'\n", (int)len,
argv[optind] + subs[0].rm_so); argv[optind] + subs[0].rm_so);
else else
printf("match `'@%.1s\n", printf("match `'@%.1s\n",
......
...@@ -219,7 +219,7 @@ int stop; /* character this ERE should end at */ ...@@ -219,7 +219,7 @@ int stop; /* character this ERE should end at */
conc = HERE(); conc = HERE();
while (MORE() && (c = PEEK()) != '|' && c != stop) while (MORE() && (c = PEEK()) != '|' && c != stop)
p_ere_exp(p); p_ere_exp(p);
REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */ if(REQUIRE(HERE() != conc, REG_EMPTY)); /* require nonempty */
if (!EAT('|')) if (!EAT('|'))
break; /* NOTE BREAK OUT */ break; /* NOTE BREAK OUT */
...@@ -266,7 +266,7 @@ register struct parse *p; ...@@ -266,7 +266,7 @@ register struct parse *p;
pos = HERE(); pos = HERE();
switch (c) { switch (c) {
case '(': case '(':
REQUIRE(MORE(), REG_EPAREN); if(REQUIRE(MORE(), REG_EPAREN));
p->g->nsub++; p->g->nsub++;
subno = (sopno) p->g->nsub; subno = (sopno) p->g->nsub;
if (subno < NPAREN) if (subno < NPAREN)
...@@ -279,7 +279,7 @@ register struct parse *p; ...@@ -279,7 +279,7 @@ register struct parse *p;
assert(p->pend[subno] != 0); assert(p->pend[subno] != 0);
} }
EMIT(ORPAREN, subno); EMIT(ORPAREN, subno);
MUSTEAT(')', REG_EPAREN); if(MUSTEAT(')', REG_EPAREN));
break; break;
#ifndef POSIX_MISTAKE #ifndef POSIX_MISTAKE
case ')': /* happens only if no current unmatched ( */ case ')': /* happens only if no current unmatched ( */
...@@ -322,12 +322,12 @@ register struct parse *p; ...@@ -322,12 +322,12 @@ register struct parse *p;
p_bracket(p); p_bracket(p);
break; break;
case '\\': case '\\':
REQUIRE(MORE(), REG_EESCAPE); if(REQUIRE(MORE(), REG_EESCAPE));
c = GETNEXT(); c = GETNEXT();
ordinary(p, c); ordinary(p, c);
break; break;
case '{': /* okay as ordinary except if digit follows */ case '{': /* okay as ordinary except if digit follows */
REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT); if(REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT));
/* FALLTHROUGH */ /* FALLTHROUGH */
default: default:
ordinary(p, c); ordinary(p, c);
...@@ -343,7 +343,7 @@ register struct parse *p; ...@@ -343,7 +343,7 @@ register struct parse *p;
return; /* no repetition, we're done */ return; /* no repetition, we're done */
NEXT(); NEXT();
REQUIRE(!wascaret, REG_BADRPT); if(REQUIRE(!wascaret, REG_BADRPT));
switch (c) { switch (c) {
case '*': /* implemented as +? */ case '*': /* implemented as +? */
/* this case does not require the (y|) trick, noKLUDGE */ /* this case does not require the (y|) trick, noKLUDGE */
...@@ -370,7 +370,7 @@ register struct parse *p; ...@@ -370,7 +370,7 @@ register struct parse *p;
if (EAT(',')) { if (EAT(',')) {
if (isdigit(PEEK())) { if (isdigit(PEEK())) {
count2 = p_count(p); count2 = p_count(p);
REQUIRE(count <= count2, REG_BADBR); if(REQUIRE(count <= count2, REG_BADBR));
} else /* single number with comma */ } else /* single number with comma */
count2 = RE_INFINITY; count2 = RE_INFINITY;
} else /* just a single number */ } else /* just a single number */
...@@ -379,7 +379,7 @@ register struct parse *p; ...@@ -379,7 +379,7 @@ register struct parse *p;
if (!EAT('}')) { /* error heuristics */ if (!EAT('}')) { /* error heuristics */
while (MORE() && PEEK() != '}') while (MORE() && PEEK() != '}')
NEXT(); NEXT();
REQUIRE(MORE(), REG_EBRACE); if(REQUIRE(MORE(), REG_EBRACE));
SETERROR(REG_BADBR); SETERROR(REG_BADBR);
} }
break; break;
...@@ -402,7 +402,7 @@ static void ...@@ -402,7 +402,7 @@ static void
p_str(p) p_str(p)
register struct parse *p; register struct parse *p;
{ {
REQUIRE(MORE(), REG_EMPTY); if(REQUIRE(MORE(), REG_EMPTY));
while (MORE()) while (MORE())
ordinary(p, GETNEXT()); ordinary(p, GETNEXT());
} }
...@@ -445,7 +445,7 @@ register int end2; /* second terminating character */ ...@@ -445,7 +445,7 @@ register int end2; /* second terminating character */
p->g->neol++; p->g->neol++;
} }
REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */ if(REQUIRE(HERE() != start, REG_EMPTY)); /* require nonempty */
} }
/* /*
...@@ -470,7 +470,7 @@ int starordinary; /* is a leading * an ordinary character? */ ...@@ -470,7 +470,7 @@ int starordinary; /* is a leading * an ordinary character? */
assert(MORE()); /* caller should have ensured this */ assert(MORE()); /* caller should have ensured this */
c = GETNEXT(); c = GETNEXT();
if (c == '\\') { if (c == '\\') {
REQUIRE(MORE(), REG_EESCAPE); if(REQUIRE(MORE(), REG_EESCAPE));
c = BACKSL | (unsigned char)GETNEXT(); c = BACKSL | (unsigned char)GETNEXT();
} }
switch (c) { switch (c) {
...@@ -500,7 +500,7 @@ int starordinary; /* is a leading * an ordinary character? */ ...@@ -500,7 +500,7 @@ int starordinary; /* is a leading * an ordinary character? */
assert(p->pend[subno] != 0); assert(p->pend[subno] != 0);
} }
EMIT(ORPAREN, subno); EMIT(ORPAREN, subno);
REQUIRE(EATTWO('\\', ')'), REG_EPAREN); if(REQUIRE(EATTWO('\\', ')'), REG_EPAREN));
break; break;
case BACKSL|')': /* should not get here -- must be user */ case BACKSL|')': /* should not get here -- must be user */
case BACKSL|'}': case BACKSL|'}':
...@@ -530,7 +530,7 @@ int starordinary; /* is a leading * an ordinary character? */ ...@@ -530,7 +530,7 @@ int starordinary; /* is a leading * an ordinary character? */
p->g->backrefs = 1; p->g->backrefs = 1;
break; break;
case '*': case '*':
REQUIRE(starordinary, REG_BADRPT); if(REQUIRE(starordinary, REG_BADRPT));
/* FALLTHROUGH */ /* FALLTHROUGH */
default: default:
ordinary(p, c &~ BACKSL); ordinary(p, c &~ BACKSL);
...@@ -548,7 +548,7 @@ int starordinary; /* is a leading * an ordinary character? */ ...@@ -548,7 +548,7 @@ int starordinary; /* is a leading * an ordinary character? */
if (EAT(',')) { if (EAT(',')) {
if (MORE() && isdigit(PEEK())) { if (MORE() && isdigit(PEEK())) {
count2 = p_count(p); count2 = p_count(p);
REQUIRE(count <= count2, REG_BADBR); if(REQUIRE(count <= count2, REG_BADBR));
} else /* single number with comma */ } else /* single number with comma */
count2 = RE_INFINITY; count2 = RE_INFINITY;
} else /* just a single number */ } else /* just a single number */
...@@ -557,7 +557,7 @@ int starordinary; /* is a leading * an ordinary character? */ ...@@ -557,7 +557,7 @@ int starordinary; /* is a leading * an ordinary character? */
if (!EATTWO('\\', '}')) { /* error heuristics */ if (!EATTWO('\\', '}')) { /* error heuristics */
while (MORE() && !SEETWO('\\', '}')) while (MORE() && !SEETWO('\\', '}'))
NEXT(); NEXT();
REQUIRE(MORE(), REG_EBRACE); if(REQUIRE(MORE(), REG_EBRACE));
SETERROR(REG_BADBR); SETERROR(REG_BADBR);
} }
} else if (c == (unsigned char)'$') /* $ (but not \$) ends it */ } else if (c == (unsigned char)'$') /* $ (but not \$) ends it */
...@@ -582,7 +582,7 @@ register struct parse *p; ...@@ -582,7 +582,7 @@ register struct parse *p;
ndigits++; ndigits++;
} }
REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR); if(REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR));
return(count); return(count);
} }
...@@ -622,7 +622,7 @@ register struct parse *p; ...@@ -622,7 +622,7 @@ register struct parse *p;
p_b_term(p, cs); p_b_term(p, cs);
if (EAT('-')) if (EAT('-'))
CHadd(cs, '-'); CHadd(cs, '-');
MUSTEAT(']', REG_EBRACK); if(MUSTEAT(']', REG_EBRACK));
if (p->error != 0) /* don't mess things up further */ if (p->error != 0) /* don't mess things up further */
return; return;
...@@ -693,21 +693,21 @@ register cset *cs; ...@@ -693,21 +693,21 @@ register cset *cs;
switch (c) { switch (c) {
case ':': /* character class */ case ':': /* character class */
NEXT2(); NEXT2();
REQUIRE(MORE(), REG_EBRACK); if(REQUIRE(MORE(), REG_EBRACK));
c = PEEK(); c = PEEK();
REQUIRE(c != '-' && c != ']', REG_ECTYPE); if(REQUIRE(c != '-' && c != ']', REG_ECTYPE));
p_b_cclass(p, cs); p_b_cclass(p, cs);
REQUIRE(MORE(), REG_EBRACK); if(REQUIRE(MORE(), REG_EBRACK));
REQUIRE(EATTWO(':', ']'), REG_ECTYPE); if(REQUIRE(EATTWO(':', ']'), REG_ECTYPE));
break; break;
case '=': /* equivalence class */ case '=': /* equivalence class */
NEXT2(); NEXT2();
REQUIRE(MORE(), REG_EBRACK); if(REQUIRE(MORE(), REG_EBRACK));
c = PEEK(); c = PEEK();
REQUIRE(c != '-' && c != ']', REG_ECOLLATE); if(REQUIRE(c != '-' && c != ']', REG_ECOLLATE));
p_b_eclass(p, cs); p_b_eclass(p, cs);
REQUIRE(MORE(), REG_EBRACK); if(REQUIRE(MORE(), REG_EBRACK));
REQUIRE(EATTWO('=', ']'), REG_ECOLLATE); if(REQUIRE(EATTWO('=', ']'), REG_ECOLLATE));
break; break;
default: /* symbol, ordinary character, or range */ default: /* symbol, ordinary character, or range */
/* xxx revision needed for multichar stuff */ /* xxx revision needed for multichar stuff */
...@@ -722,7 +722,7 @@ register cset *cs; ...@@ -722,7 +722,7 @@ register cset *cs;
} else } else
finish = start; finish = start;
/* xxx what about signed chars here... */ /* xxx what about signed chars here... */
REQUIRE(start <= finish, REG_ERANGE); if(REQUIRE(start <= finish, REG_ERANGE));
for (i = start; i <= finish; i++) for (i = start; i <= finish; i++)
CHadd(cs, i); CHadd(cs, i);
break; break;
...@@ -790,13 +790,13 @@ register struct parse *p; ...@@ -790,13 +790,13 @@ register struct parse *p;
{ {
register char value; register char value;
REQUIRE(MORE(), REG_EBRACK); if(REQUIRE(MORE(), REG_EBRACK));
if (!EATTWO('[', '.')) if (!EATTWO('[', '.'))
return(GETNEXT()); return(GETNEXT());
/* collating symbol */ /* collating symbol */
value = p_b_coll_elem(p, '.'); value = p_b_coll_elem(p, '.');
REQUIRE(EATTWO('.', ']'), REG_ECOLLATE); if(REQUIRE(EATTWO('.', ']'), REG_ECOLLATE));
return(value); return(value);
} }
......
...@@ -31,23 +31,23 @@ static struct rerr { ...@@ -31,23 +31,23 @@ static struct rerr {
char *name; char *name;
char *explain; char *explain;
} rerrs[] = { } rerrs[] = {
REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match", {REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match"},
REG_BADPAT, "REG_BADPAT", "invalid regular expression", {REG_BADPAT, "REG_BADPAT", "invalid regular expression"},
REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element", {REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element"},
REG_ECTYPE, "REG_ECTYPE", "invalid character class", {REG_ECTYPE, "REG_ECTYPE", "invalid character class"},
REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)", {REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)"},
REG_ESUBREG, "REG_ESUBREG", "invalid backreference number", {REG_ESUBREG, "REG_ESUBREG", "invalid backreference number"},
REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced", {REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced"},
REG_EPAREN, "REG_EPAREN", "parentheses not balanced", {REG_EPAREN, "REG_EPAREN", "parentheses not balanced"},
REG_EBRACE, "REG_EBRACE", "braces not balanced", {REG_EBRACE, "REG_EBRACE", "braces not balanced"},
REG_BADBR, "REG_BADBR", "invalid repetition count(s)", {REG_BADBR, "REG_BADBR", "invalid repetition count(s)"},
REG_ERANGE, "REG_ERANGE", "invalid character range", {REG_ERANGE, "REG_ERANGE", "invalid character range"},
REG_ESPACE, "REG_ESPACE", "out of memory", {REG_ESPACE, "REG_ESPACE", "out of memory"},
REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid", {REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid"},
REG_EMPTY, "REG_EMPTY", "empty (sub)expression", {REG_EMPTY, "REG_EMPTY", "empty (sub)expression"},
REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug", {REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug"},
REG_INVARG, "REG_INVARG", "invalid argument to regex routine", {REG_INVARG, "REG_INVARG", "invalid argument to regex routine"},
0, "", "*** unknown regexp error code ***", {0, "", "*** unknown regexp error code ***"},
}; };
/* /*
......
...@@ -861,7 +861,6 @@ static int merge_index(SORTPARAM *param, uchar **sort_keys, ...@@ -861,7 +861,6 @@ static int merge_index(SORTPARAM *param, uchar **sort_keys,
buffpek+maxbuffer,1)) buffpek+maxbuffer,1))
DBUG_RETURN(1); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */
DBUG_RETURN(0); DBUG_RETURN(0);
/* Was: DBUG_RETURN(my_b_write(outfile,last_ref,param->ref_length)); */
} /* merge_index */ } /* merge_index */
......
...@@ -31,10 +31,11 @@ ...@@ -31,10 +31,11 @@
#endif #endif
ulong myisam_sort_buffer_size; ulong myisam_sort_buffer_size;
myisam_recover_types myisam_recover_type= HA_RECOVER_NONE; ulong myisam_recover_options= HA_RECOVER_NONE;
/* bits in myisam_recover_options */
const char *myisam_recover_names[] = const char *myisam_recover_names[] =
{ "NO","DEFAULT", "BACKUP"}; { "DEFAULT", "BACKUP", "FORCE"};
TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names),"", TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names),"",
myisam_recover_names}; myisam_recover_names};
...@@ -152,7 +153,7 @@ int ha_myisam::dump(THD* thd, int fd) ...@@ -152,7 +153,7 @@ int ha_myisam::dump(THD* thd, int fd)
my_off_t bytes_to_read = share->state.state.data_file_length; my_off_t bytes_to_read = share->state.state.data_file_length;
int data_fd = file->dfile; int data_fd = file->dfile;
byte * buf = (byte*) my_malloc(blocksize, MYF(MY_WME)); byte * buf = (byte*) my_malloc(blocksize, MYF(MY_WME));
if(!buf) if (!buf)
return ENOMEM; return ENOMEM;
int error = 0; int error = 0;
...@@ -342,13 +343,13 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt) ...@@ -342,13 +343,13 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
char* backup_dir = thd->lex.backup_dir; char* backup_dir = thd->lex.backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN]; char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char* table_name = table->real_name; char* table_name = table->real_name;
if(!fn_format(src_path, table_name, backup_dir, MI_NAME_DEXT, 4 + 64)) if (!fn_format(src_path, table_name, backup_dir, MI_NAME_DEXT, 4 + 64))
return HA_ADMIN_INVALID; return HA_ADMIN_INVALID;
int error = 0; int error = 0;
const char* errmsg = ""; const char* errmsg = "";
if(my_copy(src_path, fn_format(dst_path, table->path, "", if (my_copy(src_path, fn_format(dst_path, table->path, "",
MI_NAME_DEXT, 4), MYF(MY_WME))) MI_NAME_DEXT, 4), MYF(MY_WME)))
{ {
error = HA_ADMIN_FAILED; error = HA_ADMIN_FAILED;
...@@ -373,24 +374,25 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt) ...@@ -373,24 +374,25 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
} }
} }
int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt) int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
{ {
char* backup_dir = thd->lex.backup_dir; char* backup_dir = thd->lex.backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN]; char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char* table_name = table->real_name; char* table_name = table->real_name;
if(!fn_format(dst_path, table_name, backup_dir, reg_ext, 4 + 64)) if (!fn_format(dst_path, table_name, backup_dir, reg_ext, 4 + 64))
return HA_ADMIN_INVALID; return HA_ADMIN_INVALID;
if(my_copy(fn_format(src_path, table->path,"", reg_ext, 4), if (my_copy(fn_format(src_path, table->path,"", reg_ext, 4),
dst_path, dst_path,
MYF(MY_WME | MY_HOLD_ORIGINAL_MODES ))) MYF(MY_WME | MY_HOLD_ORIGINAL_MODES )))
{ {
return HA_ADMIN_FAILED; return HA_ADMIN_FAILED;
} }
if(!fn_format(dst_path, table_name, backup_dir, MI_NAME_DEXT, 4 + 64)) if (!fn_format(dst_path, table_name, backup_dir, MI_NAME_DEXT, 4 + 64))
return HA_ADMIN_INVALID; return HA_ADMIN_INVALID;
if(my_copy(fn_format(src_path, table->path,"", MI_NAME_DEXT, 4), if (my_copy(fn_format(src_path, table->path,"", MI_NAME_DEXT, 4),
dst_path, dst_path,
MYF(MY_WME | MY_HOLD_ORIGINAL_MODES )) ) MYF(MY_WME | MY_HOLD_ORIGINAL_MODES )) )
return HA_ADMIN_FAILED; return HA_ADMIN_FAILED;
...@@ -572,6 +574,33 @@ bool ha_myisam::activate_all_index(THD *thd) ...@@ -572,6 +574,33 @@ bool ha_myisam::activate_all_index(THD *thd)
DBUG_RETURN(error); DBUG_RETURN(error);
} }
bool ha_myisam::check_and_repair(THD *thd, const char *name)
{
int error=0;
HA_CHECK_OPT check_opt;
DBUG_ENTER("ha_myisam::auto_check_and_repair");
if (open(name, O_RDWR, HA_OPEN_WAIT_IF_LOCKED))
DBUG_RETURN(1);
check_opt.init();
check_opt.flags=T_MEDIUM;
if (mi_is_crashed(file) || check(thd, &check_opt))
{
check_opt.flags=(((myisam_recover_options & HA_RECOVER_BACKUP) ?
T_BACKUP_DATA : 0) |
(!(myisam_recover_options & HA_RECOVER_FORCE) ?
T_SAFE_REPAIR : 0));
if (repair(thd, &check_opt))
error=1;
}
if (close())
error=1;
DBUG_RETURN(error);
}
int ha_myisam::update_row(const byte * old_data, byte * new_data) int ha_myisam::update_row(const byte * old_data, byte * new_data)
{ {
statistic_increment(ha_update_count,&LOCK_status); statistic_increment(ha_update_count,&LOCK_status);
......
...@@ -24,12 +24,14 @@ ...@@ -24,12 +24,14 @@
#include <myisam.h> #include <myisam.h>
#include <ft_global.h> #include <ft_global.h>
enum myisam_recover_types { HA_RECOVER_NONE, HA_RECOVER_DEFAULT, #define HA_RECOVER_NONE 0 // No automatic recover
HA_RECOVER_BACKUP}; #define HA_RECOVER_DEFAULT 1 // Automatic recover active
#define HA_RECOVER_BACKUP 2 // Make a backupfile on recover
#define HA_RECOVER_FORCE 4 // Recover even if we loose rows
extern ulong myisam_sort_buffer_size; extern ulong myisam_sort_buffer_size;
extern TYPELIB myisam_recover_typelib; extern TYPELIB myisam_recover_typelib;
extern myisam_recover_types myisam_recover_type; extern ulong myisam_recover_options;
class ha_myisam: public handler class ha_myisam: public handler
{ {
...@@ -39,11 +41,12 @@ class ha_myisam: public handler ...@@ -39,11 +41,12 @@ class ha_myisam: public handler
public: public:
ha_myisam(TABLE *table): handler(table), file(0), ha_myisam(TABLE *table): handler(table), file(0),
int_option_flag(HA_READ_NEXT+HA_READ_PREV+HA_READ_RND_SAME+ int_option_flag(HA_READ_NEXT | HA_READ_PREV | HA_READ_RND_SAME |
HA_KEYPOS_TO_RNDPOS+ HA_READ_ORDER+ HA_LASTKEY_ORDER+ HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER |
HA_HAVE_KEY_READ_ONLY+ HA_READ_NOT_EXACT_KEY+ HA_HAVE_KEY_READ_ONLY | HA_READ_NOT_EXACT_KEY |
HA_LONGLONG_KEYS+ HA_NULL_KEY + HA_LONGLONG_KEYS | HA_NULL_KEY |
HA_DUPP_POS + HA_BLOB_KEY + HA_AUTO_PART_KEY) HA_DUPP_POS | HA_BLOB_KEY | HA_AUTO_PART_KEY |
HA_CHECK_AND_REPAIR)
{} {}
~ha_myisam() {} ~ha_myisam() {}
const char *table_type() const { return "MyISAM"; } const char *table_type() const { return "MyISAM"; }
...@@ -100,6 +103,7 @@ class ha_myisam: public handler ...@@ -100,6 +103,7 @@ class ha_myisam: public handler
int check(THD* thd, HA_CHECK_OPT* check_opt); int check(THD* thd, HA_CHECK_OPT* check_opt);
int analyze(THD* thd,HA_CHECK_OPT* check_opt); int analyze(THD* thd,HA_CHECK_OPT* check_opt);
int repair(THD* thd, HA_CHECK_OPT* check_opt); int repair(THD* thd, HA_CHECK_OPT* check_opt);
bool check_and_repair(THD *thd, const char *name);
int optimize(THD* thd, HA_CHECK_OPT* check_opt); int optimize(THD* thd, HA_CHECK_OPT* check_opt);
int restore(THD* thd, HA_CHECK_OPT* check_opt); int restore(THD* thd, HA_CHECK_OPT* check_opt);
int backup(THD* thd, HA_CHECK_OPT* check_opt); int backup(THD* thd, HA_CHECK_OPT* check_opt);
......
...@@ -594,7 +594,7 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info, ...@@ -594,7 +594,7 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
TABLE table; TABLE table;
DBUG_ENTER("ha_create_table"); DBUG_ENTER("ha_create_table");
if (openfrm(name,"",0,(uint) READ_ALL,&table)) if (openfrm(name,"",0,(uint) READ_ALL, 0, &table))
DBUG_RETURN(1); DBUG_RETURN(1);
if (update_create_info) if (update_create_info)
{ {
......
...@@ -66,6 +66,7 @@ ...@@ -66,6 +66,7 @@
#define HA_NO_WRITE_DELAYED (HA_NOT_EXACT_COUNT*2) #define HA_NO_WRITE_DELAYED (HA_NOT_EXACT_COUNT*2)
#define HA_PRIMARY_KEY_IN_READ_INDEX (HA_NO_WRITE_DELAYED*2) #define HA_PRIMARY_KEY_IN_READ_INDEX (HA_NO_WRITE_DELAYED*2)
#define HA_DROP_BEFORE_CREATE (HA_PRIMARY_KEY_IN_READ_INDEX*2) #define HA_DROP_BEFORE_CREATE (HA_PRIMARY_KEY_IN_READ_INDEX*2)
#define HA_CHECK_AND_REPAIR (HA_DROP_BEFORE_CREATE*2)
/* Parameters for open() (in register form->filestat) */ /* Parameters for open() (in register form->filestat) */
/* HA_GET_INFO does a implicit HA_ABORT_IF_LOCKED */ /* HA_GET_INFO does a implicit HA_ABORT_IF_LOCKED */
...@@ -248,6 +249,7 @@ class handler :public Sql_alloc ...@@ -248,6 +249,7 @@ class handler :public Sql_alloc
virtual void update_create_info(HA_CREATE_INFO *create_info) {} virtual void update_create_info(HA_CREATE_INFO *create_info) {}
virtual int check(THD* thd, HA_CHECK_OPT* check_opt ); virtual int check(THD* thd, HA_CHECK_OPT* check_opt );
virtual int repair(THD* thd, HA_CHECK_OPT* check_opt); virtual int repair(THD* thd, HA_CHECK_OPT* check_opt);
virtual bool check_and_repair(THD *thd, const char *name) {return 1;}
virtual int optimize(THD* thd,HA_CHECK_OPT* check_opt); virtual int optimize(THD* thd,HA_CHECK_OPT* check_opt);
virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt); virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt);
virtual int backup(THD* thd, HA_CHECK_OPT* check_opt); virtual int backup(THD* thd, HA_CHECK_OPT* check_opt);
......
...@@ -243,7 +243,10 @@ void key_unpack(String *to,TABLE *table,uint idx) ...@@ -243,7 +243,10 @@ void key_unpack(String *to,TABLE *table,uint idx)
} }
/* Return 1 if any field in a list is part of key */ /*
Return 1 if any field in a list is part of key or the key uses a field
that is automaticly updated (like a timestamp)
*/
bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields) bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields)
{ {
...@@ -255,6 +258,10 @@ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields) ...@@ -255,6 +258,10 @@ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields)
key_part++) key_part++)
{ {
Item_field *field; Item_field *field;
if (key_part->field == table->timestamp_field)
return 1; // Can't be used for update
f.rewind(); f.rewind();
while ((field=(Item_field*) f++)) while ((field=(Item_field*) f++))
{ {
......
...@@ -531,7 +531,7 @@ int rea_create_table(my_string file_name,HA_CREATE_INFO *create_info, ...@@ -531,7 +531,7 @@ int rea_create_table(my_string file_name,HA_CREATE_INFO *create_info,
int format_number(uint inputflag,uint max_length,my_string pos,uint length, int format_number(uint inputflag,uint max_length,my_string pos,uint length,
my_string *errpos); my_string *errpos);
int openfrm(const char *name,const char *alias,uint filestat,uint prgflag, int openfrm(const char *name,const char *alias,uint filestat,uint prgflag,
TABLE *outparam); uint ha_open_flags, TABLE *outparam);
int closefrm(TABLE *table); int closefrm(TABLE *table);
db_type get_table_type(const char *name); db_type get_table_type(const char *name);
int read_string(File file, gptr *to, uint length); int read_string(File file, gptr *to, uint length);
......
...@@ -282,7 +282,7 @@ extern pthread_handler_decl(handle_slave,arg); ...@@ -282,7 +282,7 @@ extern pthread_handler_decl(handle_slave,arg);
#ifdef SET_RLIMIT_NOFILE #ifdef SET_RLIMIT_NOFILE
static uint set_maximum_open_files(uint max_file_limit); static uint set_maximum_open_files(uint max_file_limit);
#endif #endif
static ulong find_bit_type(const char *x, TYPELIB *bit_lib);
/**************************************************************************** /****************************************************************************
** Code to end mysqld ** Code to end mysqld
...@@ -1064,6 +1064,7 @@ static void init_signals(void) ...@@ -1064,6 +1064,7 @@ static void init_signals(void)
sigaddset(&set,SIGTERM); sigaddset(&set,SIGTERM);
sigaddset(&set,SIGHUP); sigaddset(&set,SIGHUP);
signal(SIGTERM,SIG_DFL); // If it's blocked by parent signal(SIGTERM,SIG_DFL); // If it's blocked by parent
signal(SIGHUP,SIG_DFL); // If it's blocked by parent
#ifdef SIGTSTP #ifdef SIGTSTP
sigaddset(&set,SIGTSTP); sigaddset(&set,SIGTSTP);
#endif #endif
...@@ -2568,6 +2569,8 @@ static void usage(void) ...@@ -2568,6 +2569,8 @@ static void usage(void)
Log slow queries to this log file. Defaults logging\n\ Log slow queries to this log file. Defaults logging\n\
to hostname-slow.log\n\ to hostname-slow.log\n\
--pid-file=path Pid file used by safe_mysqld\n\ --pid-file=path Pid file used by safe_mysqld\n\
--myisam-recover[=option[,option...]] where options is one of DEAULT,\n\
BACKUP or FORCE.\n\
--memlock Lock mysqld in memory\n\ --memlock Lock mysqld in memory\n\
-n, --new Use very new possible 'unsafe' functions\n\ -n, --new Use very new possible 'unsafe' functions\n\
-o, --old-protocol Use the old (3.20) protocol\n\ -o, --old-protocol Use the old (3.20) protocol\n\
...@@ -2856,13 +2859,13 @@ static void get_options(int argc,char **argv) ...@@ -2856,13 +2859,13 @@ static void get_options(int argc,char **argv)
default_table_type=DB_TYPE_ISAM; default_table_type=DB_TYPE_ISAM;
myisam_delay_key_write=0; myisam_delay_key_write=0;
myisam_concurrent_insert=0; myisam_concurrent_insert=0;
myisam_recover_type= HA_RECOVER_NONE; myisam_recover_options= 0;
break; break;
case (int) OPT_SAFE: case (int) OPT_SAFE:
opt_specialflag|= SPECIAL_SAFE_MODE; opt_specialflag|= SPECIAL_SAFE_MODE;
myisam_delay_key_write=0; myisam_delay_key_write=0;
myisam_concurrent_insert=0; myisam_concurrent_insert=0;
myisam_recover_type= HA_RECOVER_NONE; // For now myisam_recover_options= HA_RECOVER_NONE; // To be changed
break; break;
case (int) OPT_SKIP_CONCURRENT_INSERT: case (int) OPT_SKIP_CONCURRENT_INSERT:
myisam_concurrent_insert=0; myisam_concurrent_insert=0;
...@@ -3026,13 +3029,14 @@ static void get_options(int argc,char **argv) ...@@ -3026,13 +3029,14 @@ static void get_options(int argc,char **argv)
#endif #endif
case OPT_MYISAM_RECOVER: case OPT_MYISAM_RECOVER:
{ {
int type; if (!optarg || !optarg[0])
if ((type=find_type(optarg, &myisam_recover_typelib, 2)) <= 0) myisam_recover_options=HA_RECOVER_DEFAULT;
else if ((myisam_recover_options=
find_bit_type(optarg, &myisam_recover_typelib)) == ~(ulong) 0)
{ {
fprintf(stderr,"Unknown option to myisam-recover: %s\n",optarg); fprintf(stderr, "Unknown option to myisam-recover: %s\n",optarg);
exit(1); exit(1);
} }
myisam_recover_type=(myisam_recover_types) (type-1);
break; break;
} }
case OPT_MASTER_HOST: case OPT_MASTER_HOST:
...@@ -3568,6 +3572,64 @@ static uint set_maximum_open_files(uint max_file_limit) ...@@ -3568,6 +3572,64 @@ static uint set_maximum_open_files(uint max_file_limit)
#endif #endif
/*
Return a bitfield from a string of substrings separated by ','
returns ~(ulong) 0 on error.
*/
static ulong find_bit_type(const char *x, TYPELIB *bit_lib)
{
bool found_end;
int found_count;
const char *end,*i,*j;
const char **array, *pos;
ulong found,found_int,bit;
DBUG_ENTER("find_bit_type");
DBUG_PRINT("enter",("x: '%s'",x));
found=0;
found_end= 0;
pos=(my_string) x;
do
{
if (!*(end=strcend(pos,','))) /* Let end point at fieldend */
{
while (end > pos && end[-1] == ' ')
end--; /* Skipp end-space */
found_end=1;
}
found_int=0; found_count=0;
for (array=bit_lib->type_names, bit=1 ; (i= *array++) ; bit<<=1)
{
j=pos;
while (j != end)
{
if (toupper(*i++) != toupper(*j++))
goto skipp;
}
found_int=bit;
if (! *i)
{
found_count=1;
break;
}
else if (j != pos) // Half field found
{
found_count++; // Could be one of two values
}
skipp: ;
}
if (found_count != 1)
DBUG_RETURN(~(ulong) 0); // No unique value
found|=found_int;
pos=end+1;
} while (! found_end);
DBUG_PRINT("exit",("bit-field: %ld",(ulong) found));
DBUG_RETURN(found);
} /* find_bit_type */
/***************************************************************************** /*****************************************************************************
** Instantiate templates ** Instantiate templates
*****************************************************************************/ *****************************************************************************/
......
...@@ -675,7 +675,7 @@ void close_thread_tables(THD *thd, bool locked) ...@@ -675,7 +675,7 @@ void close_thread_tables(THD *thd, bool locked)
} }
thd->open_tables=0; thd->open_tables=0;
/* Free tables to hold down open files */ /* Free tables to hold down open files */
while (open_cache.records >= table_cache_size && unused_tables) while (open_cache.records > table_cache_size && unused_tables)
VOID(hash_delete(&open_cache,(byte*) unused_tables)); /* purecov: tested */ VOID(hash_delete(&open_cache,(byte*) unused_tables)); /* purecov: tested */
check_unused(); check_unused();
if (found_old_table) if (found_old_table)
...@@ -987,7 +987,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, ...@@ -987,7 +987,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
else else
{ {
/* Free cache if too big */ /* Free cache if too big */
while (open_cache.records >= table_cache_size && unused_tables) while (open_cache.records > table_cache_size && unused_tables)
VOID(hash_delete(&open_cache,(byte*) unused_tables)); /* purecov: tested */ VOID(hash_delete(&open_cache,(byte*) unused_tables)); /* purecov: tested */
/* make a new table */ /* make a new table */
...@@ -1410,6 +1410,7 @@ static int open_unireg_entry(TABLE *entry,const char *db,const char *name, ...@@ -1410,6 +1410,7 @@ static int open_unireg_entry(TABLE *entry,const char *db,const char *name,
(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX | (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX |
HA_TRY_READ_ONLY), HA_TRY_READ_ONLY),
READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD, READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
ha_open_options,
entry)) entry))
{ {
DBUG_RETURN(1); DBUG_RETURN(1);
...@@ -1575,6 +1576,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db, ...@@ -1575,6 +1576,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX | (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX |
HA_TRY_READ_ONLY), HA_TRY_READ_ONLY),
READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD, READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
ha_open_options,
tmp_table)) tmp_table))
{ {
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -1859,6 +1861,7 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields, ...@@ -1859,6 +1861,7 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
DBUG_RETURN(-1); /* purecov: inspected */ DBUG_RETURN(-1); /* purecov: inspected */
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
item->split_sum_func(*sum_func_list); item->split_sum_func(*sum_func_list);
thd->used_tables|=item->used_tables();
} }
} }
DBUG_RETURN(test(thd->fatal_error)); DBUG_RETURN(test(thd->fatal_error));
......
...@@ -88,6 +88,7 @@ THD::THD() ...@@ -88,6 +88,7 @@ THD::THD()
open_tables=temporary_tables=0; open_tables=temporary_tables=0;
tmp_table=0; tmp_table=0;
lock=locked_tables=0; lock=locked_tables=0;
used_tables=0;
cuted_fields=0L; cuted_fields=0L;
options=thd_startup_options; options=thd_startup_options;
update_lock_default= low_priority_updates ? TL_WRITE_LOW_PRIORITY : TL_WRITE; update_lock_default= low_priority_updates ? TL_WRITE_LOW_PRIORITY : TL_WRITE;
......
...@@ -263,6 +263,7 @@ class THD :public ilink { ...@@ -263,6 +263,7 @@ class THD :public ilink {
ulonglong next_insert_id,last_insert_id,current_insert_id; ulonglong next_insert_id,last_insert_id,current_insert_id;
ha_rows select_limit,offset_limit,default_select_limit,cuted_fields, ha_rows select_limit,offset_limit,default_select_limit,cuted_fields,
max_join_size,sent_row_count; max_join_size,sent_row_count;
table_map used_tables;
ulong query_id,version, inactive_timeout,options,thread_id; ulong query_id,version, inactive_timeout,options,thread_id;
long dbug_thread_id; long dbug_thread_id;
pthread_t real_id; pthread_t real_id;
......
...@@ -140,6 +140,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, ...@@ -140,6 +140,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
if (!table) if (!table)
DBUG_RETURN(-1); DBUG_RETURN(-1);
thd->proc_info="init"; thd->proc_info="init";
thd->used_tables=0;
save_time_stamp=table->time_stamp; save_time_stamp=table->time_stamp;
values= its++; values= its++;
if (check_insert_fields(thd,table,fields,*values,1) || if (check_insert_fields(thd,table,fields,*values,1) ||
...@@ -200,6 +201,9 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, ...@@ -200,6 +201,9 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
} }
else else
{ {
if (thd->used_tables) // Column used in values()
restore_record(table,2); // Get empty record
else
table->record[0][0]=table->record[2][0]; // Fix delete marker table->record[0][0]=table->record[2][0]; // Fix delete marker
if (fill_record(table->field,*values)) if (fill_record(table->field,*values))
{ {
...@@ -1166,12 +1170,7 @@ select_insert::prepare(List<Item> &values) ...@@ -1166,12 +1170,7 @@ select_insert::prepare(List<Item> &values)
if (check_insert_fields(thd,table,*fields,values,1)) if (check_insert_fields(thd,table,*fields,values,1))
DBUG_RETURN(1); DBUG_RETURN(1);
if (fields->elements)
{
restore_record(table,2); // Get empty record restore_record(table,2); // Get empty record
}
else
table->record[0][0]=table->record[2][0]; // Fix delete marker
table->next_number_field=table->found_next_number_field; table->next_number_field=table->found_next_number_field;
thd->count_cuted_fields=1; /* calc cuted fields */ thd->count_cuted_fields=1; /* calc cuted fields */
thd->cuted_fields=0; thd->cuted_fields=0;
......
...@@ -40,7 +40,7 @@ static byte* get_field_name(Field *buff,uint *length, ...@@ -40,7 +40,7 @@ static byte* get_field_name(Field *buff,uint *length,
/* Open a .frm file */ /* Open a .frm file */
int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
TABLE *outparam) uint ha_open_flags, TABLE *outparam)
{ {
reg1 uint i; reg1 uint i;
reg2 uchar *strpos; reg2 uchar *strpos;
...@@ -216,12 +216,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -216,12 +216,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
ha_open(index_file, ha_open(index_file,
(db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR), (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
(db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE : (db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
db_stat & HA_WAIT_IF_LOCKED || (db_stat & HA_WAIT_IF_LOCKED ||
specialflag & SPECIAL_WAIT_IF_LOCKED ? specialflag & SPECIAL_WAIT_IF_LOCKED) ?
HA_OPEN_WAIT_IF_LOCKED : HA_OPEN_WAIT_IF_LOCKED :
(db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ? (db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
HA_OPEN_ABORT_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED :
HA_OPEN_IGNORE_IF_LOCKED) | ha_open_options))) HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags)))
goto err_not_open; /* purecov: inspected */ goto err_not_open; /* purecov: inspected */
} }
outparam->db_low_byte_first=outparam->file->low_byte_first(); outparam->db_low_byte_first=outparam->file->low_byte_first();
......
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