mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
Merge bk-internal:/home/bk/mysql-5.0-maint
into neptunus.(none):/home/msvensson/mysql/mysql-5.0-maint
This commit is contained in:
commit
6e70b126ed
68 changed files with 2614 additions and 465 deletions
|
@ -122,10 +122,10 @@ ADD_SUBDIRECTORY(myisam)
|
|||
ADD_SUBDIRECTORY(myisammrg)
|
||||
ADD_SUBDIRECTORY(client)
|
||||
IF(WITH_BERKELEY_STORAGE_ENGINE)
|
||||
ADD_SUBDIRECTORY(bdb)
|
||||
ADD_SUBDIRECTORY(bdb)
|
||||
ENDIF(WITH_BERKELEY_STORAGE_ENGINE)
|
||||
IF(WITH_INNOBASE_STORAGE_ENGINE)
|
||||
ADD_SUBDIRECTORY(innobase)
|
||||
ADD_SUBDIRECTORY(innobase)
|
||||
ENDIF(WITH_INNOBASE_STORAGE_ENGINE)
|
||||
ADD_SUBDIRECTORY(sql)
|
||||
ADD_SUBDIRECTORY(sql/examples)
|
||||
|
|
|
@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc)
|
|||
AC_CANONICAL_SYSTEM
|
||||
# The Docs Makefile.am parses this line!
|
||||
# remember to also change ndb version below and update version.c in ndb
|
||||
AM_INIT_AUTOMAKE(mysql, 5.0.27)
|
||||
AM_INIT_AUTOMAKE(mysql, 5.0.29)
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
|
||||
PROTOCOL_VERSION=10
|
||||
|
@ -19,7 +19,7 @@ SHARED_LIB_VERSION=$SHARED_LIB_MAJOR_VERSION:0:0
|
|||
# ndb version
|
||||
NDB_VERSION_MAJOR=5
|
||||
NDB_VERSION_MINOR=0
|
||||
NDB_VERSION_BUILD=27
|
||||
NDB_VERSION_BUILD=29
|
||||
NDB_VERSION_STATUS=""
|
||||
|
||||
# Set all version vars based on $VERSION. How do we do this more elegant ?
|
||||
|
|
|
@ -112,6 +112,8 @@ enum my_lex_states
|
|||
|
||||
struct charset_info_st;
|
||||
|
||||
|
||||
/* See strings/CHARSET_INFO.txt for information about this structure */
|
||||
typedef struct my_collation_handler_st
|
||||
{
|
||||
my_bool (*init)(struct charset_info_st *, void *(*alloc)(uint));
|
||||
|
@ -154,6 +156,7 @@ extern MY_COLLATION_HANDLER my_collation_8bit_simple_ci_handler;
|
|||
extern MY_COLLATION_HANDLER my_collation_ucs2_uca_handler;
|
||||
|
||||
|
||||
/* See strings/CHARSET_INFO.txt about information on this structure */
|
||||
typedef struct my_charset_handler_st
|
||||
{
|
||||
my_bool (*init)(struct charset_info_st *, void *(*alloc)(uint));
|
||||
|
@ -216,6 +219,7 @@ extern MY_CHARSET_HANDLER my_charset_8bit_handler;
|
|||
extern MY_CHARSET_HANDLER my_charset_ucs2_handler;
|
||||
|
||||
|
||||
/* See strings/CHARSET_INFO.txt about information on this structure */
|
||||
typedef struct charset_info_st
|
||||
{
|
||||
uint number;
|
||||
|
|
|
@ -224,12 +224,17 @@ enum ha_base_keytype {
|
|||
/* poor old NISAM has 8-bit flags :-( */
|
||||
#define HA_SORT_ALLOWS_SAME 128 /* Intern bit when sorting records */
|
||||
#endif
|
||||
#if MYSQL_VERSION_ID < 0x50200
|
||||
/*
|
||||
Key has a part that can have end space. If this is an unique key
|
||||
we have to handle it differently from other unique keys as we can find
|
||||
many matching rows for one key (because end space are not compared)
|
||||
*/
|
||||
#define HA_END_SPACE_KEY 4096
|
||||
#define HA_END_SPACE_KEY 0 /* was: 4096 */
|
||||
#else
|
||||
#error HA_END_SPACE_KEY is obsolete, please remove it
|
||||
#endif
|
||||
|
||||
|
||||
/* These flags can be added to key-seg-flag */
|
||||
|
||||
|
|
|
@ -351,12 +351,18 @@ typedef int (*IO_CACHE_CALLBACK)(struct st_io_cache*);
|
|||
#ifdef THREAD
|
||||
typedef struct st_io_cache_share
|
||||
{
|
||||
/* to sync on reads into buffer */
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
int count, total;
|
||||
/* actual IO_CACHE that filled the buffer */
|
||||
struct st_io_cache *active;
|
||||
pthread_mutex_t mutex; /* To sync on reads into buffer. */
|
||||
pthread_cond_t cond; /* To wait for signals. */
|
||||
pthread_cond_t cond_writer; /* For a synchronized writer. */
|
||||
/* Offset in file corresponding to the first byte of buffer. */
|
||||
my_off_t pos_in_file;
|
||||
/* If a synchronized write cache is the source of the data. */
|
||||
struct st_io_cache *source_cache;
|
||||
byte *buffer; /* The read buffer. */
|
||||
byte *read_end; /* Behind last valid byte of buffer. */
|
||||
int running_threads; /* threads not in lock. */
|
||||
int total_threads; /* threads sharing the cache. */
|
||||
int error; /* Last error. */
|
||||
#ifdef NOT_YET_IMPLEMENTED
|
||||
/* whether the structure should be free'd */
|
||||
my_bool alloced;
|
||||
|
@ -720,8 +726,8 @@ extern void setup_io_cache(IO_CACHE* info);
|
|||
extern int _my_b_read(IO_CACHE *info,byte *Buffer,uint Count);
|
||||
#ifdef THREAD
|
||||
extern int _my_b_read_r(IO_CACHE *info,byte *Buffer,uint Count);
|
||||
extern void init_io_cache_share(IO_CACHE *info,
|
||||
IO_CACHE_SHARE *s, uint num_threads);
|
||||
extern void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare,
|
||||
IO_CACHE *write_cache, uint num_threads);
|
||||
extern void remove_io_thread(IO_CACHE *info);
|
||||
#endif
|
||||
extern int _my_b_seq_read(IO_CACHE *info,byte *Buffer,uint Count);
|
||||
|
|
|
@ -419,7 +419,7 @@ typedef struct st_mi_check_param
|
|||
uint testflag, key_cache_block_size;
|
||||
uint8 language;
|
||||
my_bool using_global_keycache, opt_lock_memory, opt_follow_links;
|
||||
my_bool retry_repair, force_sort, calc_checksum;
|
||||
my_bool retry_repair, force_sort;
|
||||
char temp_filename[FN_REFLEN],*isam_file_name;
|
||||
MY_TMPDIR *tmpdir;
|
||||
int tmpfile_createflag;
|
||||
|
|
|
@ -16,6 +16,31 @@
|
|||
|
||||
/* Describe, check and repair of MyISAM tables */
|
||||
|
||||
/*
|
||||
About checksum calculation.
|
||||
|
||||
There are two types of checksums. Table checksum and row checksum.
|
||||
|
||||
Row checksum is an additional byte at the end of dynamic length
|
||||
records. It must be calculated if the table is configured for them.
|
||||
Otherwise they must not be used. The variable
|
||||
MYISAM_SHARE::calc_checksum determines if row checksums are used.
|
||||
MI_INFO::checksum is used as temporary storage during row handling.
|
||||
For parallel repair we must assure that only one thread can use this
|
||||
variable. There is no problem on the write side as this is done by one
|
||||
thread only. But when checking a record after read this could go
|
||||
wrong. But since all threads read through a common read buffer, it is
|
||||
sufficient if only one thread checks it.
|
||||
|
||||
Table checksum is an eight byte value in the header of the index file.
|
||||
It can be calculated even if row checksums are not used. The variable
|
||||
MI_CHECK::glob_crc is calculated over all records.
|
||||
MI_SORT_PARAM::calc_checksum determines if this should be done. This
|
||||
variable is not part of MI_CHECK because it must be set per thread for
|
||||
parallel repair. The global glob_crc must be changed by one thread
|
||||
only. And it is sufficient to calculate the checksum once only.
|
||||
*/
|
||||
|
||||
#include "ftdefs.h"
|
||||
#include <m_ctype.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -41,8 +66,7 @@ static int chk_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo,
|
|||
ha_checksum *key_checksum, uint level);
|
||||
static uint isam_key_length(MI_INFO *info,MI_KEYDEF *keyinfo);
|
||||
static ha_checksum calc_checksum(ha_rows count);
|
||||
static int writekeys(MI_CHECK *param, MI_INFO *info,byte *buff,
|
||||
my_off_t filepos);
|
||||
static int writekeys(MI_SORT_PARAM *sort_param);
|
||||
static int sort_one_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo,
|
||||
my_off_t pagepos, File new_file);
|
||||
static int sort_key_read(MI_SORT_PARAM *sort_param,void *key);
|
||||
|
@ -1102,7 +1126,8 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
|
|||
goto err;
|
||||
start_recpos=pos;
|
||||
splits++;
|
||||
VOID(_mi_pack_get_block_info(info,&block_info, -1, start_recpos));
|
||||
VOID(_mi_pack_get_block_info(info, &info->bit_buff, &block_info,
|
||||
&info->rec_buff, -1, start_recpos));
|
||||
pos=block_info.filepos+block_info.rec_len;
|
||||
if (block_info.rec_len < (uint) info->s->min_pack_length ||
|
||||
block_info.rec_len > (uint) info->s->max_pack_length)
|
||||
|
@ -1116,7 +1141,8 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
|
|||
if (_mi_read_cache(¶m->read_cache,(byte*) info->rec_buff,
|
||||
block_info.filepos, block_info.rec_len, READING_NEXT))
|
||||
goto err;
|
||||
if (_mi_pack_rec_unpack(info,record,info->rec_buff,block_info.rec_len))
|
||||
if (_mi_pack_rec_unpack(info, &info->bit_buff, record,
|
||||
info->rec_buff, block_info.rec_len))
|
||||
{
|
||||
mi_check_print_error(param,"Found wrong record at %s",
|
||||
llstr(start_recpos,llbuff));
|
||||
|
@ -1400,7 +1426,7 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
|
|||
info->state->empty=0;
|
||||
param->glob_crc=0;
|
||||
if (param->testflag & T_CALC_CHECKSUM)
|
||||
param->calc_checksum=1;
|
||||
sort_param.calc_checksum= 1;
|
||||
|
||||
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
|
||||
|
||||
|
@ -1429,7 +1455,7 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
|
|||
/* Re-create all keys, which are set in key_map. */
|
||||
while (!(error=sort_get_next_record(&sort_param)))
|
||||
{
|
||||
if (writekeys(param,info,(byte*)sort_param.record,sort_param.filepos))
|
||||
if (writekeys(&sort_param))
|
||||
{
|
||||
if (my_errno != HA_ERR_FOUND_DUPP_KEY)
|
||||
goto err;
|
||||
|
@ -1574,11 +1600,13 @@ err:
|
|||
|
||||
/* Uppate keyfile when doing repair */
|
||||
|
||||
static int writekeys(MI_CHECK *param, register MI_INFO *info, byte *buff,
|
||||
my_off_t filepos)
|
||||
static int writekeys(MI_SORT_PARAM *sort_param)
|
||||
{
|
||||
register uint i;
|
||||
uchar *key;
|
||||
uchar *key;
|
||||
MI_INFO *info= sort_param->sort_info->info;
|
||||
byte *buff= sort_param->record;
|
||||
my_off_t filepos= sort_param->filepos;
|
||||
DBUG_ENTER("writekeys");
|
||||
|
||||
key=info->lastkey+info->s->base.max_key_length;
|
||||
|
@ -1632,8 +1660,8 @@ static int writekeys(MI_CHECK *param, register MI_INFO *info, byte *buff,
|
|||
}
|
||||
}
|
||||
/* Remove checksum that was added to glob_crc in sort_get_next_record */
|
||||
if (param->calc_checksum)
|
||||
param->glob_crc-= info->checksum;
|
||||
if (sort_param->calc_checksum)
|
||||
sort_param->sort_info->param->glob_crc-= info->checksum;
|
||||
DBUG_PRINT("error",("errno: %d",my_errno));
|
||||
DBUG_RETURN(-1);
|
||||
} /* writekeys */
|
||||
|
@ -2139,7 +2167,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
|
|||
del=info->state->del;
|
||||
param->glob_crc=0;
|
||||
if (param->testflag & T_CALC_CHECKSUM)
|
||||
param->calc_checksum=1;
|
||||
sort_param.calc_checksum= 1;
|
||||
|
||||
rec_per_key_part= param->rec_per_key_part;
|
||||
for (sort_param.key=0 ; sort_param.key < share->base.keys ;
|
||||
|
@ -2201,7 +2229,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
|
|||
param->retry_repair=1;
|
||||
goto err;
|
||||
}
|
||||
param->calc_checksum=0; /* No need to calc glob_crc */
|
||||
/* No need to calculate checksum again. */
|
||||
sort_param.calc_checksum= 0;
|
||||
|
||||
/* Set for next loop */
|
||||
sort_info.max_records= (ha_rows) info->state->records;
|
||||
|
@ -2364,6 +2393,28 @@ err:
|
|||
Each key is handled by a separate thread.
|
||||
TODO: make a number of threads a parameter
|
||||
|
||||
In parallel repair we use one thread per index. There are two modes:
|
||||
|
||||
Quick
|
||||
|
||||
Only the indexes are rebuilt. All threads share a read buffer.
|
||||
Every thread that needs fresh data in the buffer enters the shared
|
||||
cache lock. The last thread joining the lock reads the buffer from
|
||||
the data file and wakes all other threads.
|
||||
|
||||
Non-quick
|
||||
|
||||
The data file is rebuilt and all indexes are rebuilt to point to
|
||||
the new record positions. One thread is the master thread. It
|
||||
reads from the old data file and writes to the new data file. It
|
||||
also creates one of the indexes. The other threads read from a
|
||||
buffer which is filled by the master. If they need fresh data,
|
||||
they enter the shared cache lock. If the masters write buffer is
|
||||
full, it flushes it to the new data file and enters the shared
|
||||
cache lock too. When all threads joined in the lock, the master
|
||||
copies its write buffer to the read buffer for the other threads
|
||||
and wakes them.
|
||||
|
||||
RESULT
|
||||
0 ok
|
||||
<>0 Error
|
||||
|
@ -2386,6 +2437,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
|
|||
ulong *rec_per_key_part;
|
||||
HA_KEYSEG *keyseg;
|
||||
char llbuff[22];
|
||||
IO_CACHE new_data_cache; /* For non-quick repair. */
|
||||
IO_CACHE_SHARE io_share;
|
||||
SORT_INFO sort_info;
|
||||
ulonglong key_map=share->state.key_map;
|
||||
|
@ -2407,19 +2459,55 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
|
|||
if (info->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
|
||||
param->testflag|=T_CALC_CHECKSUM;
|
||||
|
||||
/*
|
||||
Quick repair (not touching data file, rebuilding indexes):
|
||||
{
|
||||
Read cache is (MI_CHECK *param)->read_cache using info->dfile.
|
||||
}
|
||||
|
||||
Non-quick repair (rebuilding data file and indexes):
|
||||
{
|
||||
Master thread:
|
||||
|
||||
Read cache is (MI_CHECK *param)->read_cache using info->dfile.
|
||||
Write cache is (MI_INFO *info)->rec_cache using new_file.
|
||||
|
||||
Slave threads:
|
||||
|
||||
Read cache is new_data_cache synced to master rec_cache.
|
||||
|
||||
The final assignment of the filedescriptor for rec_cache is done
|
||||
after the cache creation.
|
||||
|
||||
Don't check file size on new_data_cache, as the resulting file size
|
||||
is not known yet.
|
||||
|
||||
As rec_cache and new_data_cache are synced, write_buffer_length is
|
||||
used for the read cache 'new_data_cache'. Both start at the same
|
||||
position 'new_header_length'.
|
||||
}
|
||||
*/
|
||||
DBUG_PRINT("info", ("is quick repair: %d", rep_quick));
|
||||
bzero((char*)&sort_info,sizeof(sort_info));
|
||||
/* Initialize pthread structures before goto err. */
|
||||
pthread_mutex_init(&sort_info.mutex, MY_MUTEX_INIT_FAST);
|
||||
pthread_cond_init(&sort_info.cond, 0);
|
||||
|
||||
if (!(sort_info.key_block=
|
||||
alloc_key_blocks(param,
|
||||
(uint) param->sort_key_blocks,
|
||||
share->base.max_key_block_length))
|
||||
|| init_io_cache(¶m->read_cache,info->dfile,
|
||||
(uint) param->read_buffer_length,
|
||||
READ_CACHE,share->pack.header_length,1,MYF(MY_WME)) ||
|
||||
(! rep_quick &&
|
||||
init_io_cache(&info->rec_cache,info->dfile,
|
||||
(uint) param->write_buffer_length,
|
||||
WRITE_CACHE,new_header_length,1,
|
||||
MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw)))
|
||||
alloc_key_blocks(param, (uint) param->sort_key_blocks,
|
||||
share->base.max_key_block_length)) ||
|
||||
init_io_cache(¶m->read_cache, info->dfile,
|
||||
(uint) param->read_buffer_length,
|
||||
READ_CACHE, share->pack.header_length, 1, MYF(MY_WME)) ||
|
||||
(!rep_quick &&
|
||||
(init_io_cache(&info->rec_cache, info->dfile,
|
||||
(uint) param->write_buffer_length,
|
||||
WRITE_CACHE, new_header_length, 1,
|
||||
MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw) ||
|
||||
init_io_cache(&new_data_cache, -1,
|
||||
(uint) param->write_buffer_length,
|
||||
READ_CACHE, new_header_length, 1,
|
||||
MYF(MY_WME | MY_DONT_CHECK_FILESIZE)))))
|
||||
goto err;
|
||||
sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks;
|
||||
info->opt_flag|=WRITE_CACHE_USED;
|
||||
|
@ -2510,8 +2598,6 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
|
|||
|
||||
del=info->state->del;
|
||||
param->glob_crc=0;
|
||||
if (param->testflag & T_CALC_CHECKSUM)
|
||||
param->calc_checksum=1;
|
||||
|
||||
if (!(sort_param=(MI_SORT_PARAM *)
|
||||
my_malloc((uint) share->base.keys *
|
||||
|
@ -2561,6 +2647,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
|
|||
sort_param[i].sort_info=&sort_info;
|
||||
sort_param[i].master=0;
|
||||
sort_param[i].fix_datafile=0;
|
||||
sort_param[i].calc_checksum= 0;
|
||||
|
||||
sort_param[i].filepos=new_header_length;
|
||||
sort_param[i].max_pos=sort_param[i].pos=share->pack.header_length;
|
||||
|
@ -2597,19 +2684,45 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
|
|||
sort_info.total_keys=i;
|
||||
sort_param[0].master= 1;
|
||||
sort_param[0].fix_datafile= (my_bool)(! rep_quick);
|
||||
sort_param[0].calc_checksum= test(param->testflag & T_CALC_CHECKSUM);
|
||||
|
||||
sort_info.got_error=0;
|
||||
pthread_mutex_init(&sort_info.mutex, MY_MUTEX_INIT_FAST);
|
||||
pthread_cond_init(&sort_info.cond, 0);
|
||||
pthread_mutex_lock(&sort_info.mutex);
|
||||
|
||||
init_io_cache_share(¶m->read_cache, &io_share, i);
|
||||
/*
|
||||
Initialize the I/O cache share for use with the read caches and, in
|
||||
case of non-quick repair, the write cache. When all threads join on
|
||||
the cache lock, the writer copies the write cache contents to the
|
||||
read caches.
|
||||
*/
|
||||
if (i > 1)
|
||||
{
|
||||
if (rep_quick)
|
||||
init_io_cache_share(¶m->read_cache, &io_share, NULL, i);
|
||||
else
|
||||
init_io_cache_share(&new_data_cache, &io_share, &info->rec_cache, i);
|
||||
}
|
||||
else
|
||||
io_share.total_threads= 0; /* share not used */
|
||||
|
||||
(void) pthread_attr_init(&thr_attr);
|
||||
(void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
|
||||
|
||||
for (i=0 ; i < sort_info.total_keys ; i++)
|
||||
{
|
||||
sort_param[i].read_cache=param->read_cache;
|
||||
/*
|
||||
Copy the properly initialized IO_CACHE structure so that every
|
||||
thread has its own copy. In quick mode param->read_cache is shared
|
||||
for use by all threads. In non-quick mode all threads but the
|
||||
first copy the shared new_data_cache, which is synchronized to the
|
||||
write cache of the first thread. The first thread copies
|
||||
param->read_cache, which is not shared.
|
||||
*/
|
||||
sort_param[i].read_cache= ((rep_quick || !i) ? param->read_cache :
|
||||
new_data_cache);
|
||||
DBUG_PRINT("io_cache_share", ("thread: %u read_cache: 0x%lx",
|
||||
i, (long) &sort_param[i].read_cache));
|
||||
|
||||
/*
|
||||
two approaches: the same amount of memory for each thread
|
||||
or the memory for the same number of keys for each thread...
|
||||
|
@ -2627,7 +2740,10 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
|
|||
(void *) (sort_param+i)))
|
||||
{
|
||||
mi_check_print_error(param,"Cannot start a repair thread");
|
||||
remove_io_thread(¶m->read_cache);
|
||||
/* Cleanup: Detach from the share. Avoid others to be blocked. */
|
||||
if (io_share.total_threads)
|
||||
remove_io_thread(&sort_param[i].read_cache);
|
||||
DBUG_PRINT("error", ("Cannot start a repair thread"));
|
||||
sort_info.got_error=1;
|
||||
}
|
||||
else
|
||||
|
@ -2649,6 +2765,11 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
|
|||
|
||||
if (sort_param[0].fix_datafile)
|
||||
{
|
||||
/*
|
||||
Append some nuls to the end of a memory mapped file. Destroy the
|
||||
write cache. The master thread did already detach from the share
|
||||
by remove_io_thread() in sort.c:thr_find_all_keys().
|
||||
*/
|
||||
if (write_data_suffix(&sort_info,1) || end_io_cache(&info->rec_cache))
|
||||
goto err;
|
||||
if (param->testflag & T_SAFE_REPAIR)
|
||||
|
@ -2664,8 +2785,14 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
|
|||
sort_param->filepos;
|
||||
/* Only whole records */
|
||||
share->state.version=(ulong) time((time_t*) 0);
|
||||
|
||||
/*
|
||||
Exchange the data file descriptor of the table, so that we use the
|
||||
new file from now on.
|
||||
*/
|
||||
my_close(info->dfile,MYF(0));
|
||||
info->dfile=new_file;
|
||||
|
||||
share->data_file_type=sort_info.new_data_file_type;
|
||||
share->pack.header_length=(ulong) new_header_length;
|
||||
}
|
||||
|
@ -2720,7 +2847,20 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
|
|||
|
||||
err:
|
||||
got_error|= flush_blocks(param, share->key_cache, share->kfile);
|
||||
/*
|
||||
Destroy the write cache. The master thread did already detach from
|
||||
the share by remove_io_thread() or it was not yet started (if the
|
||||
error happend before creating the thread).
|
||||
*/
|
||||
VOID(end_io_cache(&info->rec_cache));
|
||||
/*
|
||||
Destroy the new data cache in case of non-quick repair. All slave
|
||||
threads did either detach from the share by remove_io_thread()
|
||||
already or they were not yet started (if the error happend before
|
||||
creating the threads).
|
||||
*/
|
||||
if (!rep_quick)
|
||||
VOID(end_io_cache(&new_data_cache));
|
||||
if (!got_error)
|
||||
{
|
||||
/* Replace the actual file with the temporary file */
|
||||
|
@ -2851,12 +2991,41 @@ static int sort_ft_key_read(MI_SORT_PARAM *sort_param, void *key)
|
|||
} /* sort_ft_key_read */
|
||||
|
||||
|
||||
/* Read next record from file using parameters in sort_info */
|
||||
/* Return -1 if end of file, 0 if ok and > 0 if error */
|
||||
/*
|
||||
Read next record from file using parameters in sort_info.
|
||||
|
||||
SYNOPSIS
|
||||
sort_get_next_record()
|
||||
sort_param Information about and for the sort process
|
||||
|
||||
NOTE
|
||||
|
||||
Dynamic Records With Non-Quick Parallel Repair
|
||||
|
||||
For non-quick parallel repair we use a synchronized read/write
|
||||
cache. This means that one thread is the master who fixes the data
|
||||
file by reading each record from the old data file and writing it
|
||||
to the new data file. By doing this the records in the new data
|
||||
file are written contiguously. Whenever the write buffer is full,
|
||||
it is copied to the read buffer. The slaves read from the read
|
||||
buffer, which is not associated with a file. Thus read_cache.file
|
||||
is -1. When using _mi_read_cache(), the slaves must always set
|
||||
flag to READING_NEXT so that the function never tries to read from
|
||||
file. This is safe because the records are contiguous. There is no
|
||||
need to read outside the cache. This condition is evaluated in the
|
||||
variable 'parallel_flag' for quick reference. read_cache.file must
|
||||
be >= 0 in every other case.
|
||||
|
||||
RETURN
|
||||
-1 end of file
|
||||
0 ok
|
||||
> 0 error
|
||||
*/
|
||||
|
||||
static int sort_get_next_record(MI_SORT_PARAM *sort_param)
|
||||
{
|
||||
int searching;
|
||||
int parallel_flag;
|
||||
uint found_record,b_type,left_length;
|
||||
my_off_t pos;
|
||||
byte *to;
|
||||
|
@ -2894,7 +3063,7 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
|
|||
sort_param->max_pos=(sort_param->pos+=share->base.pack_reclength);
|
||||
if (*sort_param->record)
|
||||
{
|
||||
if (param->calc_checksum)
|
||||
if (sort_param->calc_checksum)
|
||||
param->glob_crc+= (info->checksum=
|
||||
mi_static_checksum(info,sort_param->record));
|
||||
DBUG_RETURN(0);
|
||||
|
@ -2909,6 +3078,7 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
|
|||
LINT_INIT(to);
|
||||
pos=sort_param->pos;
|
||||
searching=(sort_param->fix_datafile && (param->testflag & T_EXTEND));
|
||||
parallel_flag= (sort_param->read_cache.file < 0) ? READING_NEXT : 0;
|
||||
for (;;)
|
||||
{
|
||||
found_record=block_info.second_read= 0;
|
||||
|
@ -2939,7 +3109,7 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
|
|||
(byte*) block_info.header,pos,
|
||||
MI_BLOCK_INFO_HEADER_LENGTH,
|
||||
(! found_record ? READING_NEXT : 0) |
|
||||
READING_HEADER))
|
||||
parallel_flag | READING_HEADER))
|
||||
{
|
||||
if (found_record)
|
||||
{
|
||||
|
@ -3116,9 +3286,31 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
|
|||
llstr(sort_param->start_recpos,llbuff));
|
||||
goto try_next;
|
||||
}
|
||||
if (_mi_read_cache(&sort_param->read_cache,to,block_info.filepos,
|
||||
block_info.data_len,
|
||||
(found_record == 1 ? READING_NEXT : 0)))
|
||||
/*
|
||||
Copy information that is already read. Avoid accessing data
|
||||
below the cache start. This could happen if the header
|
||||
streched over the end of the previous buffer contents.
|
||||
*/
|
||||
{
|
||||
uint header_len= (uint) (block_info.filepos - pos);
|
||||
uint prefetch_len= (MI_BLOCK_INFO_HEADER_LENGTH - header_len);
|
||||
|
||||
if (prefetch_len > block_info.data_len)
|
||||
prefetch_len= block_info.data_len;
|
||||
if (prefetch_len)
|
||||
{
|
||||
memcpy(to, block_info.header + header_len, prefetch_len);
|
||||
block_info.filepos+= prefetch_len;
|
||||
block_info.data_len-= prefetch_len;
|
||||
left_length-= prefetch_len;
|
||||
to+= prefetch_len;
|
||||
}
|
||||
}
|
||||
if (block_info.data_len &&
|
||||
_mi_read_cache(&sort_param->read_cache,to,block_info.filepos,
|
||||
block_info.data_len,
|
||||
(found_record == 1 ? READING_NEXT : 0) |
|
||||
parallel_flag))
|
||||
{
|
||||
mi_check_print_info(param,
|
||||
"Read error for block at: %s (error: %d); Skipped",
|
||||
|
@ -3148,13 +3340,14 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
|
|||
{
|
||||
if (sort_param->read_cache.error < 0)
|
||||
DBUG_RETURN(1);
|
||||
if (info->s->calc_checksum)
|
||||
info->checksum=mi_checksum(info,sort_param->record);
|
||||
if (sort_param->calc_checksum)
|
||||
info->checksum= mi_checksum(info, sort_param->record);
|
||||
if ((param->testflag & (T_EXTEND | T_REP)) || searching)
|
||||
{
|
||||
if (_mi_rec_check(info, sort_param->record, sort_param->rec_buff,
|
||||
sort_param->find_length,
|
||||
(param->testflag & T_QUICK) &&
|
||||
sort_param->calc_checksum &&
|
||||
test(info->s->calc_checksum)))
|
||||
{
|
||||
mi_check_print_info(param,"Found wrong packed record at %s",
|
||||
|
@ -3162,7 +3355,7 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
|
|||
goto try_next;
|
||||
}
|
||||
}
|
||||
if (param->calc_checksum)
|
||||
if (sort_param->calc_checksum)
|
||||
param->glob_crc+= info->checksum;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
@ -3189,7 +3382,8 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
|
|||
DBUG_RETURN(1); /* Something wrong with data */
|
||||
}
|
||||
sort_param->start_recpos=sort_param->pos;
|
||||
if (_mi_pack_get_block_info(info,&block_info,-1,sort_param->pos))
|
||||
if (_mi_pack_get_block_info(info, &sort_param->bit_buff, &block_info,
|
||||
&sort_param->rec_buff, -1, sort_param->pos))
|
||||
DBUG_RETURN(-1);
|
||||
if (!block_info.rec_len &&
|
||||
sort_param->pos + MEMMAP_EXTRA_MARGIN ==
|
||||
|
@ -3213,15 +3407,14 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
|
|||
llstr(sort_param->pos,llbuff));
|
||||
continue;
|
||||
}
|
||||
if (_mi_pack_rec_unpack(info,sort_param->record,sort_param->rec_buff,
|
||||
block_info.rec_len))
|
||||
if (_mi_pack_rec_unpack(info, &sort_param->bit_buff, sort_param->record,
|
||||
sort_param->rec_buff, block_info.rec_len))
|
||||
{
|
||||
if (! searching)
|
||||
mi_check_print_info(param,"Found wrong record at %s",
|
||||
llstr(sort_param->pos,llbuff));
|
||||
continue;
|
||||
}
|
||||
info->checksum=mi_checksum(info,sort_param->record);
|
||||
if (!sort_param->fix_datafile)
|
||||
{
|
||||
sort_param->filepos=sort_param->pos;
|
||||
|
@ -3231,8 +3424,9 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
|
|||
sort_param->max_pos=(sort_param->pos=block_info.filepos+
|
||||
block_info.rec_len);
|
||||
info->packed_length=block_info.rec_len;
|
||||
if (param->calc_checksum)
|
||||
param->glob_crc+= info->checksum;
|
||||
if (sort_param->calc_checksum)
|
||||
param->glob_crc+= (info->checksum=
|
||||
mi_checksum(info, sort_param->record));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
|
@ -3240,7 +3434,20 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
|
|||
}
|
||||
|
||||
|
||||
/* Write record to new file */
|
||||
/*
|
||||
Write record to new file.
|
||||
|
||||
SYNOPSIS
|
||||
sort_write_record()
|
||||
sort_param Sort parameters.
|
||||
|
||||
NOTE
|
||||
This is only called by a master thread if parallel repair is used.
|
||||
|
||||
RETURN
|
||||
0 OK
|
||||
1 Error
|
||||
*/
|
||||
|
||||
int sort_write_record(MI_SORT_PARAM *sort_param)
|
||||
{
|
||||
|
@ -3289,6 +3496,7 @@ int sort_write_record(MI_SORT_PARAM *sort_param)
|
|||
}
|
||||
from=sort_info->buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER);
|
||||
}
|
||||
/* We can use info->checksum here as only one thread calls this. */
|
||||
info->checksum=mi_checksum(info,sort_param->record);
|
||||
reclength=_mi_rec_pack(info,from,sort_param->record);
|
||||
flag=0;
|
||||
|
@ -3698,7 +3906,7 @@ static int sort_delete_record(MI_SORT_PARAM *sort_param)
|
|||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
if (param->calc_checksum)
|
||||
if (sort_param->calc_checksum)
|
||||
param->glob_crc-=(*info->s->calc_checksum)(info, sort_param->record);
|
||||
}
|
||||
error=flush_io_cache(&info->rec_cache) || (*info->s->delete_record)(info);
|
||||
|
|
|
@ -208,7 +208,10 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
|
|||
((open_flags & HA_OPEN_ABORT_IF_CRASHED) &&
|
||||
(my_disable_locking && share->state.open_count))))
|
||||
{
|
||||
DBUG_PRINT("error",("Table is marked as crashed"));
|
||||
DBUG_PRINT("error",("Table is marked as crashed. open_flags: %u "
|
||||
"changed: %u open_count: %u !locking: %d",
|
||||
open_flags, share->state.changed,
|
||||
share->state.open_count, my_disable_locking));
|
||||
my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
|
||||
HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
|
||||
goto err;
|
||||
|
|
|
@ -103,7 +103,8 @@ static uint fill_and_get_bits(MI_BIT_BUFF *bit_buff,uint count);
|
|||
static void fill_buffer(MI_BIT_BUFF *bit_buff);
|
||||
static uint max_bit(uint value);
|
||||
#ifdef HAVE_MMAP
|
||||
static uchar *_mi_mempack_get_block_info(MI_INFO *myisam,MI_BLOCK_INFO *info,
|
||||
static uchar *_mi_mempack_get_block_info(MI_INFO *myisam, MI_BIT_BUFF *bit_buff,
|
||||
MI_BLOCK_INFO *info, byte **rec_buff_p,
|
||||
uchar *header);
|
||||
#endif
|
||||
|
||||
|
@ -449,13 +450,15 @@ int _mi_read_pack_record(MI_INFO *info, my_off_t filepos, byte *buf)
|
|||
DBUG_RETURN(-1); /* _search() didn't find record */
|
||||
|
||||
file=info->dfile;
|
||||
if (_mi_pack_get_block_info(info, &block_info, file, filepos))
|
||||
if (_mi_pack_get_block_info(info, &info->bit_buff, &block_info,
|
||||
&info->rec_buff, file, filepos))
|
||||
goto err;
|
||||
if (my_read(file,(byte*) info->rec_buff + block_info.offset ,
|
||||
block_info.rec_len - block_info.offset, MYF(MY_NABP)))
|
||||
goto panic;
|
||||
info->update|= HA_STATE_AKTIV;
|
||||
DBUG_RETURN(_mi_pack_rec_unpack(info,buf,info->rec_buff,block_info.rec_len));
|
||||
DBUG_RETURN(_mi_pack_rec_unpack(info, &info->bit_buff, buf,
|
||||
info->rec_buff, block_info.rec_len));
|
||||
panic:
|
||||
my_errno=HA_ERR_WRONG_IN_RECORD;
|
||||
err:
|
||||
|
@ -464,8 +467,8 @@ err:
|
|||
|
||||
|
||||
|
||||
int _mi_pack_rec_unpack(register MI_INFO *info, register byte *to, byte *from,
|
||||
ulong reclength)
|
||||
int _mi_pack_rec_unpack(register MI_INFO *info, MI_BIT_BUFF *bit_buff,
|
||||
register byte *to, byte *from, ulong reclength)
|
||||
{
|
||||
byte *end_field;
|
||||
reg3 MI_COLUMNDEF *end;
|
||||
|
@ -473,18 +476,18 @@ int _mi_pack_rec_unpack(register MI_INFO *info, register byte *to, byte *from,
|
|||
MYISAM_SHARE *share=info->s;
|
||||
DBUG_ENTER("_mi_pack_rec_unpack");
|
||||
|
||||
init_bit_buffer(&info->bit_buff, (uchar*) from,reclength);
|
||||
init_bit_buffer(bit_buff, (uchar*) from, reclength);
|
||||
|
||||
for (current_field=share->rec, end=current_field+share->base.fields ;
|
||||
current_field < end ;
|
||||
current_field++,to=end_field)
|
||||
{
|
||||
end_field=to+current_field->length;
|
||||
(*current_field->unpack)(current_field,&info->bit_buff,(uchar*) to,
|
||||
(*current_field->unpack)(current_field, bit_buff, (uchar*) to,
|
||||
(uchar*) end_field);
|
||||
}
|
||||
if (! info->bit_buff.error &&
|
||||
info->bit_buff.pos - info->bit_buff.bits/8 == info->bit_buff.end)
|
||||
if (!bit_buff->error &&
|
||||
bit_buff->pos - bit_buff->bits / 8 == bit_buff->end)
|
||||
DBUG_RETURN(0);
|
||||
info->update&= ~HA_STATE_AKTIV;
|
||||
DBUG_RETURN(my_errno=HA_ERR_WRONG_IN_RECORD);
|
||||
|
@ -1015,13 +1018,16 @@ int _mi_read_rnd_pack_record(MI_INFO *info, byte *buf,
|
|||
|
||||
if (info->opt_flag & READ_CACHE_USED)
|
||||
{
|
||||
if (_mi_read_cache(&info->rec_cache,(byte*) block_info.header,filepos,
|
||||
share->pack.ref_length, skip_deleted_blocks))
|
||||
if (_mi_read_cache(&info->rec_cache, (byte*) block_info.header,
|
||||
filepos, share->pack.ref_length,
|
||||
skip_deleted_blocks ? READING_NEXT : 0))
|
||||
goto err;
|
||||
b_type=_mi_pack_get_block_info(info,&block_info,-1, filepos);
|
||||
b_type=_mi_pack_get_block_info(info, &info->bit_buff, &block_info,
|
||||
&info->rec_buff, -1, filepos);
|
||||
}
|
||||
else
|
||||
b_type=_mi_pack_get_block_info(info,&block_info,info->dfile,filepos);
|
||||
b_type=_mi_pack_get_block_info(info, &info->bit_buff, &block_info,
|
||||
&info->rec_buff, info->dfile, filepos);
|
||||
if (b_type)
|
||||
goto err; /* Error code is already set */
|
||||
#ifndef DBUG_OFF
|
||||
|
@ -1034,9 +1040,9 @@ int _mi_read_rnd_pack_record(MI_INFO *info, byte *buf,
|
|||
|
||||
if (info->opt_flag & READ_CACHE_USED)
|
||||
{
|
||||
if (_mi_read_cache(&info->rec_cache,(byte*) info->rec_buff,
|
||||
block_info.filepos, block_info.rec_len,
|
||||
skip_deleted_blocks))
|
||||
if (_mi_read_cache(&info->rec_cache, (byte*) info->rec_buff,
|
||||
block_info.filepos, block_info.rec_len,
|
||||
skip_deleted_blocks ? READING_NEXT : 0))
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
|
@ -1051,8 +1057,8 @@ int _mi_read_rnd_pack_record(MI_INFO *info, byte *buf,
|
|||
info->nextpos=block_info.filepos+block_info.rec_len;
|
||||
info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
|
||||
|
||||
DBUG_RETURN (_mi_pack_rec_unpack(info,buf,info->rec_buff,
|
||||
block_info.rec_len));
|
||||
DBUG_RETURN (_mi_pack_rec_unpack(info, &info->bit_buff, buf,
|
||||
info->rec_buff, block_info.rec_len));
|
||||
err:
|
||||
DBUG_RETURN(my_errno);
|
||||
}
|
||||
|
@ -1060,8 +1066,9 @@ int _mi_read_rnd_pack_record(MI_INFO *info, byte *buf,
|
|||
|
||||
/* Read and process header from a huff-record-file */
|
||||
|
||||
uint _mi_pack_get_block_info(MI_INFO *myisam, MI_BLOCK_INFO *info, File file,
|
||||
my_off_t filepos)
|
||||
uint _mi_pack_get_block_info(MI_INFO *myisam, MI_BIT_BUFF *bit_buff,
|
||||
MI_BLOCK_INFO *info, byte **rec_buff_p,
|
||||
File file, my_off_t filepos)
|
||||
{
|
||||
uchar *header=info->header;
|
||||
uint head_length,ref_length;
|
||||
|
@ -1086,17 +1093,17 @@ uint _mi_pack_get_block_info(MI_INFO *myisam, MI_BLOCK_INFO *info, File file,
|
|||
head_length+= read_pack_length((uint) myisam->s->pack.version,
|
||||
header + head_length, &info->blob_len);
|
||||
if (!(mi_alloc_rec_buff(myisam,info->rec_len + info->blob_len,
|
||||
&myisam->rec_buff)))
|
||||
rec_buff_p)))
|
||||
return BLOCK_FATAL_ERROR; /* not enough memory */
|
||||
myisam->bit_buff.blob_pos=(uchar*) myisam->rec_buff+info->rec_len;
|
||||
myisam->bit_buff.blob_end= myisam->bit_buff.blob_pos+info->blob_len;
|
||||
bit_buff->blob_pos= (uchar*) *rec_buff_p + info->rec_len;
|
||||
bit_buff->blob_end= bit_buff->blob_pos + info->blob_len;
|
||||
myisam->blob_length=info->blob_len;
|
||||
}
|
||||
info->filepos=filepos+head_length;
|
||||
if (file > 0)
|
||||
{
|
||||
info->offset=min(info->rec_len, ref_length - head_length);
|
||||
memcpy(myisam->rec_buff, header+head_length, info->offset);
|
||||
memcpy(*rec_buff_p, header + head_length, info->offset);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1237,7 +1244,8 @@ void _mi_unmap_file(MI_INFO *info)
|
|||
}
|
||||
|
||||
|
||||
static uchar *_mi_mempack_get_block_info(MI_INFO *myisam,MI_BLOCK_INFO *info,
|
||||
static uchar *_mi_mempack_get_block_info(MI_INFO *myisam, MI_BIT_BUFF *bit_buff,
|
||||
MI_BLOCK_INFO *info, byte **rec_buff_p,
|
||||
uchar *header)
|
||||
{
|
||||
header+= read_pack_length((uint) myisam->s->pack.version, header,
|
||||
|
@ -1248,10 +1256,10 @@ static uchar *_mi_mempack_get_block_info(MI_INFO *myisam,MI_BLOCK_INFO *info,
|
|||
&info->blob_len);
|
||||
/* mi_alloc_rec_buff sets my_errno on error */
|
||||
if (!(mi_alloc_rec_buff(myisam, info->blob_len,
|
||||
&myisam->rec_buff)))
|
||||
rec_buff_p)))
|
||||
return 0; /* not enough memory */
|
||||
myisam->bit_buff.blob_pos=(uchar*) myisam->rec_buff;
|
||||
myisam->bit_buff.blob_end= (uchar*) myisam->rec_buff + info->blob_len;
|
||||
bit_buff->blob_pos= (uchar*) *rec_buff_p;
|
||||
bit_buff->blob_end= (uchar*) *rec_buff_p + info->blob_len;
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
@ -1267,11 +1275,13 @@ static int _mi_read_mempack_record(MI_INFO *info, my_off_t filepos, byte *buf)
|
|||
if (filepos == HA_OFFSET_ERROR)
|
||||
DBUG_RETURN(-1); /* _search() didn't find record */
|
||||
|
||||
if (!(pos= (byte*) _mi_mempack_get_block_info(info,&block_info,
|
||||
if (!(pos= (byte*) _mi_mempack_get_block_info(info, &info->bit_buff,
|
||||
&block_info, &info->rec_buff,
|
||||
(uchar*) share->file_map+
|
||||
filepos)))
|
||||
DBUG_RETURN(-1);
|
||||
DBUG_RETURN(_mi_pack_rec_unpack(info, buf, pos, block_info.rec_len));
|
||||
DBUG_RETURN(_mi_pack_rec_unpack(info, &info->bit_buff, buf,
|
||||
pos, block_info.rec_len));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1291,7 +1301,8 @@ static int _mi_read_rnd_mempack_record(MI_INFO *info, byte *buf,
|
|||
my_errno=HA_ERR_END_OF_FILE;
|
||||
goto err;
|
||||
}
|
||||
if (!(pos= (byte*) _mi_mempack_get_block_info(info,&block_info,
|
||||
if (!(pos= (byte*) _mi_mempack_get_block_info(info, &info->bit_buff,
|
||||
&block_info, &info->rec_buff,
|
||||
(uchar*)
|
||||
(start=share->file_map+
|
||||
filepos))))
|
||||
|
@ -1308,7 +1319,8 @@ static int _mi_read_rnd_mempack_record(MI_INFO *info, byte *buf,
|
|||
info->nextpos=filepos+(uint) (pos-start)+block_info.rec_len;
|
||||
info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
|
||||
|
||||
DBUG_RETURN (_mi_pack_rec_unpack(info,buf,pos, block_info.rec_len));
|
||||
DBUG_RETURN (_mi_pack_rec_unpack(info, &info->bit_buff, buf,
|
||||
pos, block_info.rec_len));
|
||||
err:
|
||||
DBUG_RETURN(my_errno);
|
||||
}
|
||||
|
|
|
@ -71,6 +71,21 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, key_range *min_key,
|
|||
uchar * key_buff;
|
||||
uint start_key_len;
|
||||
|
||||
/*
|
||||
The problem is that the optimizer doesn't support
|
||||
RTree keys properly at the moment.
|
||||
Hope this will be fixed some day.
|
||||
But now NULL in the min_key means that we
|
||||
didn't make the task for the RTree key
|
||||
and expect BTree functionality from it.
|
||||
As it's not able to handle such request
|
||||
we return the error.
|
||||
*/
|
||||
if (!min_key)
|
||||
{
|
||||
res= HA_POS_ERROR;
|
||||
break;
|
||||
}
|
||||
key_buff= info->lastkey+info->s->base.max_key_length;
|
||||
start_key_len= _mi_pack_key(info,inx, key_buff,
|
||||
(uchar*) min_key->key, min_key->length,
|
||||
|
|
|
@ -76,6 +76,7 @@ typedef struct st_mi_state_info
|
|||
ulong sec_index_changed; /* Updated when new sec_index */
|
||||
ulong sec_index_used; /* which extra index are in use */
|
||||
ulonglong key_map; /* Which keys are in use */
|
||||
ha_checksum checksum; /* Table checksum */
|
||||
ulong version; /* timestamp of create */
|
||||
time_t create_time; /* Time when created database */
|
||||
time_t recover_time; /* Time for last recover */
|
||||
|
@ -176,6 +177,7 @@ typedef struct st_mi_isam_share { /* Shared between opens */
|
|||
int (*delete_record)(struct st_myisam_info*);
|
||||
int (*read_rnd)(struct st_myisam_info*, byte*, my_off_t, my_bool);
|
||||
int (*compare_record)(struct st_myisam_info*, const byte *);
|
||||
/* Function to use for a row checksum. */
|
||||
ha_checksum (*calc_checksum)(struct st_myisam_info*, const byte *);
|
||||
int (*compare_unique)(struct st_myisam_info*, MI_UNIQUEDEF *,
|
||||
const byte *record, my_off_t pos);
|
||||
|
@ -249,7 +251,7 @@ struct st_myisam_info {
|
|||
my_off_t last_keypage; /* Last key page read */
|
||||
my_off_t last_search_keypage; /* Last keypage when searching */
|
||||
my_off_t dupp_key_pos;
|
||||
ha_checksum checksum;
|
||||
ha_checksum checksum; /* Temp storage for row checksum */
|
||||
/* QQ: the folloing two xxx_length fields should be removed,
|
||||
as they are not compatible with parallel repair */
|
||||
ulong packed_length,blob_length; /* Length of found, packed record */
|
||||
|
@ -301,8 +303,9 @@ typedef struct st_mi_sort_param
|
|||
pthread_t thr;
|
||||
IO_CACHE read_cache, tempfile, tempfile_for_exceptions;
|
||||
DYNAMIC_ARRAY buffpek;
|
||||
|
||||
/*
|
||||
MI_BIT_BUFF bit_buff; /* For parallel repair of packrec. */
|
||||
|
||||
/*
|
||||
The next two are used to collect statistics, see update_key_parts for
|
||||
description.
|
||||
*/
|
||||
|
@ -313,6 +316,7 @@ typedef struct st_mi_sort_param
|
|||
uint key, key_length,real_key_length,sortbuff_size;
|
||||
uint maxbuffers, keys, find_length, sort_keys_length;
|
||||
my_bool fix_datafile, master;
|
||||
my_bool calc_checksum; /* calculate table checksum */
|
||||
MI_KEYDEF *keyinfo;
|
||||
HA_KEYSEG *seg;
|
||||
SORT_INFO *sort_info;
|
||||
|
@ -365,8 +369,15 @@ typedef struct st_mi_sort_param
|
|||
#define mi_putint(x,y,nod) { uint16 boh=(nod ? (uint16) 32768 : 0) + (uint16) (y);\
|
||||
mi_int2store(x,boh); }
|
||||
#define mi_test_if_nod(x) (x[0] & 128 ? info->s->base.key_reflength : 0)
|
||||
#define mi_mark_crashed(x) (x)->s->state.changed|=STATE_CRASHED
|
||||
#define mi_mark_crashed_on_repair(x) { (x)->s->state.changed|=STATE_CRASHED|STATE_CRASHED_ON_REPAIR ; (x)->update|= HA_STATE_CHANGED; }
|
||||
#define mi_mark_crashed(x) do{(x)->s->state.changed|= STATE_CRASHED; \
|
||||
DBUG_PRINT("error", ("Marked table crashed")); \
|
||||
}while(0)
|
||||
#define mi_mark_crashed_on_repair(x) do{(x)->s->state.changed|= \
|
||||
STATE_CRASHED|STATE_CRASHED_ON_REPAIR; \
|
||||
(x)->update|= HA_STATE_CHANGED; \
|
||||
DBUG_PRINT("error", \
|
||||
("Marked table crashed")); \
|
||||
}while(0)
|
||||
#define mi_is_crashed(x) ((x)->s->state.changed & STATE_CRASHED)
|
||||
#define mi_is_crashed_on_repair(x) ((x)->s->state.changed & STATE_CRASHED_ON_REPAIR)
|
||||
#define mi_print_error(SHARE, ERRNO) \
|
||||
|
@ -606,8 +617,8 @@ extern void _mi_print_key(FILE *stream,HA_KEYSEG *keyseg,const uchar *key,
|
|||
extern my_bool _mi_read_pack_info(MI_INFO *info,pbool fix_keys);
|
||||
extern int _mi_read_pack_record(MI_INFO *info,my_off_t filepos,byte *buf);
|
||||
extern int _mi_read_rnd_pack_record(MI_INFO*, byte *,my_off_t, my_bool);
|
||||
extern int _mi_pack_rec_unpack(MI_INFO *info,byte *to,byte *from,
|
||||
ulong reclength);
|
||||
extern int _mi_pack_rec_unpack(MI_INFO *info, MI_BIT_BUFF *bit_buff,
|
||||
byte *to, byte *from, ulong reclength);
|
||||
extern ulonglong mi_safe_mul(ulonglong a,ulonglong b);
|
||||
extern int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf,
|
||||
const byte *oldrec, const byte *newrec, my_off_t pos);
|
||||
|
@ -672,7 +683,9 @@ extern "C" {
|
|||
|
||||
extern uint _mi_get_block_info(MI_BLOCK_INFO *,File, my_off_t);
|
||||
extern uint _mi_rec_pack(MI_INFO *info,byte *to,const byte *from);
|
||||
extern uint _mi_pack_get_block_info(MI_INFO *, MI_BLOCK_INFO *, File, my_off_t);
|
||||
extern uint _mi_pack_get_block_info(MI_INFO *myisam, MI_BIT_BUFF *bit_buff,
|
||||
MI_BLOCK_INFO *info, byte **rec_buff_p,
|
||||
File file, my_off_t filepos);
|
||||
extern void _my_store_blob_length(byte *pos,uint pack_length,uint length);
|
||||
extern void _myisam_log(enum myisam_log_commands command,MI_INFO *info,
|
||||
const byte *buffert,uint length);
|
||||
|
|
134
myisam/sort.c
134
myisam/sort.c
|
@ -148,7 +148,8 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
|
|||
skr=maxbuffer;
|
||||
if (memavl < sizeof(BUFFPEK)*(uint) maxbuffer ||
|
||||
(keys=(memavl-sizeof(BUFFPEK)*(uint) maxbuffer)/
|
||||
(sort_length+sizeof(char*))) <= 1)
|
||||
(sort_length+sizeof(char*))) <= 1 ||
|
||||
keys < (uint) maxbuffer)
|
||||
{
|
||||
mi_check_print_error(info->sort_info->param,
|
||||
"sort_buffer_size is to small");
|
||||
|
@ -309,7 +310,7 @@ static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys,
|
|||
|
||||
pthread_handler_t thr_find_all_keys(void *arg)
|
||||
{
|
||||
MI_SORT_PARAM *info= (MI_SORT_PARAM*) arg;
|
||||
MI_SORT_PARAM *sort_param= (MI_SORT_PARAM*) arg;
|
||||
int error;
|
||||
uint memavl,old_memavl,keys,sort_length;
|
||||
uint idx, maxbuffer;
|
||||
|
@ -321,32 +322,34 @@ pthread_handler_t thr_find_all_keys(void *arg)
|
|||
|
||||
if (my_thread_init())
|
||||
goto err;
|
||||
if (info->sort_info->got_error)
|
||||
DBUG_ENTER("thr_find_all_keys");
|
||||
DBUG_PRINT("enter", ("master: %d", sort_param->master));
|
||||
if (sort_param->sort_info->got_error)
|
||||
goto err;
|
||||
|
||||
if (info->keyinfo->flag & HA_VAR_LENGTH_KEY)
|
||||
if (sort_param->keyinfo->flag & HA_VAR_LENGTH_KEY)
|
||||
{
|
||||
info->write_keys=write_keys_varlen;
|
||||
info->read_to_buffer=read_to_buffer_varlen;
|
||||
info->write_key=write_merge_key_varlen;
|
||||
sort_param->write_keys= write_keys_varlen;
|
||||
sort_param->read_to_buffer= read_to_buffer_varlen;
|
||||
sort_param->write_key= write_merge_key_varlen;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->write_keys=write_keys;
|
||||
info->read_to_buffer=read_to_buffer;
|
||||
info->write_key=write_merge_key;
|
||||
sort_param->write_keys= write_keys;
|
||||
sort_param->read_to_buffer= read_to_buffer;
|
||||
sort_param->write_key= write_merge_key;
|
||||
}
|
||||
|
||||
my_b_clear(&info->tempfile);
|
||||
my_b_clear(&info->tempfile_for_exceptions);
|
||||
bzero((char*) &info->buffpek,sizeof(info->buffpek));
|
||||
bzero((char*) &info->unique, sizeof(info->unique));
|
||||
my_b_clear(&sort_param->tempfile);
|
||||
my_b_clear(&sort_param->tempfile_for_exceptions);
|
||||
bzero((char*) &sort_param->buffpek, sizeof(sort_param->buffpek));
|
||||
bzero((char*) &sort_param->unique, sizeof(sort_param->unique));
|
||||
sort_keys= (uchar **) NULL;
|
||||
|
||||
memavl=max(info->sortbuff_size, MIN_SORT_MEMORY);
|
||||
idx= info->sort_info->max_records;
|
||||
sort_length= info->key_length;
|
||||
maxbuffer= 1;
|
||||
memavl= max(sort_param->sortbuff_size, MIN_SORT_MEMORY);
|
||||
idx= sort_param->sort_info->max_records;
|
||||
sort_length= sort_param->key_length;
|
||||
maxbuffer= 1;
|
||||
|
||||
while (memavl >= MIN_SORT_MEMORY)
|
||||
{
|
||||
|
@ -361,20 +364,22 @@ pthread_handler_t thr_find_all_keys(void *arg)
|
|||
skr=maxbuffer;
|
||||
if (memavl < sizeof(BUFFPEK)*maxbuffer ||
|
||||
(keys=(memavl-sizeof(BUFFPEK)*maxbuffer)/
|
||||
(sort_length+sizeof(char*))) <= 1)
|
||||
(sort_length+sizeof(char*))) <= 1 ||
|
||||
keys < (uint) maxbuffer)
|
||||
{
|
||||
mi_check_print_error(info->sort_info->param,
|
||||
mi_check_print_error(sort_param->sort_info->param,
|
||||
"sort_buffer_size is to small");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
while ((maxbuffer= (int) (idx/(keys-1)+1)) != skr);
|
||||
}
|
||||
if ((sort_keys=(uchar **)my_malloc(keys*(sort_length+sizeof(char*))+
|
||||
((info->keyinfo->flag & HA_FULLTEXT) ?
|
||||
HA_FT_MAXBYTELEN : 0), MYF(0))))
|
||||
if ((sort_keys= (uchar**)
|
||||
my_malloc(keys*(sort_length+sizeof(char*))+
|
||||
((sort_param->keyinfo->flag & HA_FULLTEXT) ?
|
||||
HA_FT_MAXBYTELEN : 0), MYF(0))))
|
||||
{
|
||||
if (my_init_dynamic_array(&info->buffpek, sizeof(BUFFPEK),
|
||||
if (my_init_dynamic_array(&sort_param->buffpek, sizeof(BUFFPEK),
|
||||
maxbuffer, maxbuffer/2))
|
||||
{
|
||||
my_free((gptr) sort_keys,MYF(0));
|
||||
|
@ -389,69 +394,87 @@ pthread_handler_t thr_find_all_keys(void *arg)
|
|||
}
|
||||
if (memavl < MIN_SORT_MEMORY)
|
||||
{
|
||||
mi_check_print_error(info->sort_info->param,"Sort buffer to small"); /* purecov: tested */
|
||||
mi_check_print_error(sort_param->sort_info->param, "Sort buffer too small");
|
||||
goto err; /* purecov: tested */
|
||||
}
|
||||
|
||||
if (info->sort_info->param->testflag & T_VERBOSE)
|
||||
printf("Key %d - Allocating buffer for %d keys\n",info->key+1,keys);
|
||||
info->sort_keys=sort_keys;
|
||||
if (sort_param->sort_info->param->testflag & T_VERBOSE)
|
||||
printf("Key %d - Allocating buffer for %d keys\n",
|
||||
sort_param->key + 1, keys);
|
||||
sort_param->sort_keys= sort_keys;
|
||||
|
||||
idx=error=0;
|
||||
sort_keys[0]=(uchar*) (sort_keys+keys);
|
||||
|
||||
while (!(error=info->sort_info->got_error) &&
|
||||
!(error=(*info->key_read)(info,sort_keys[idx])))
|
||||
DBUG_PRINT("info", ("reading keys"));
|
||||
while (!(error= sort_param->sort_info->got_error) &&
|
||||
!(error= (*sort_param->key_read)(sort_param, sort_keys[idx])))
|
||||
{
|
||||
if (info->real_key_length > info->key_length)
|
||||
if (sort_param->real_key_length > sort_param->key_length)
|
||||
{
|
||||
if (write_key(info,sort_keys[idx], &info->tempfile_for_exceptions))
|
||||
if (write_key(sort_param, sort_keys[idx],
|
||||
&sort_param->tempfile_for_exceptions))
|
||||
goto err;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (++idx == keys)
|
||||
{
|
||||
if (info->write_keys(info,sort_keys,idx-1,
|
||||
(BUFFPEK *)alloc_dynamic(&info->buffpek),
|
||||
&info->tempfile))
|
||||
if (sort_param->write_keys(sort_param, sort_keys, idx - 1,
|
||||
(BUFFPEK*) alloc_dynamic(&sort_param->buffpek),
|
||||
&sort_param->tempfile))
|
||||
goto err;
|
||||
sort_keys[0]=(uchar*) (sort_keys+keys);
|
||||
memcpy(sort_keys[0],sort_keys[idx-1],(size_t) info->key_length);
|
||||
memcpy(sort_keys[0], sort_keys[idx - 1], (size_t) sort_param->key_length);
|
||||
idx=1;
|
||||
}
|
||||
sort_keys[idx]=sort_keys[idx-1]+info->key_length;
|
||||
sort_keys[idx]= sort_keys[idx - 1] + sort_param->key_length;
|
||||
}
|
||||
if (error > 0)
|
||||
goto err;
|
||||
if (info->buffpek.elements)
|
||||
if (sort_param->buffpek.elements)
|
||||
{
|
||||
if (info->write_keys(info,sort_keys, idx,
|
||||
(BUFFPEK *) alloc_dynamic(&info->buffpek), &info->tempfile))
|
||||
if (sort_param->write_keys(sort_param, sort_keys, idx,
|
||||
(BUFFPEK*) alloc_dynamic(&sort_param->buffpek),
|
||||
&sort_param->tempfile))
|
||||
goto err;
|
||||
info->keys=(info->buffpek.elements-1)*(keys-1)+idx;
|
||||
sort_param->keys= (sort_param->buffpek.elements - 1) * (keys - 1) + idx;
|
||||
}
|
||||
else
|
||||
info->keys=idx;
|
||||
sort_param->keys= idx;
|
||||
|
||||
info->sort_keys_length=keys;
|
||||
sort_param->sort_keys_length= keys;
|
||||
goto ok;
|
||||
|
||||
err:
|
||||
info->sort_info->got_error=1; /* no need to protect this with a mutex */
|
||||
DBUG_PRINT("error", ("got some error"));
|
||||
sort_param->sort_info->got_error= 1; /* no need to protect with a mutex */
|
||||
if (sort_keys)
|
||||
my_free((gptr) sort_keys,MYF(0));
|
||||
info->sort_keys=0;
|
||||
delete_dynamic(& info->buffpek);
|
||||
close_cached_file(&info->tempfile);
|
||||
close_cached_file(&info->tempfile_for_exceptions);
|
||||
sort_param->sort_keys= 0;
|
||||
delete_dynamic(& sort_param->buffpek);
|
||||
close_cached_file(&sort_param->tempfile);
|
||||
close_cached_file(&sort_param->tempfile_for_exceptions);
|
||||
|
||||
ok:
|
||||
remove_io_thread(&info->read_cache);
|
||||
pthread_mutex_lock(&info->sort_info->mutex);
|
||||
info->sort_info->threads_running--;
|
||||
pthread_cond_signal(&info->sort_info->cond);
|
||||
pthread_mutex_unlock(&info->sort_info->mutex);
|
||||
/*
|
||||
Detach from the share if the writer is involved. Avoid others to
|
||||
be blocked. This includes a flush of the write buffer. This will
|
||||
also indicate EOF to the readers.
|
||||
*/
|
||||
if (sort_param->sort_info->info->rec_cache.share)
|
||||
remove_io_thread(&sort_param->sort_info->info->rec_cache);
|
||||
|
||||
/* Readers detach from the share if any. Avoid others to be blocked. */
|
||||
if (sort_param->read_cache.share)
|
||||
remove_io_thread(&sort_param->read_cache);
|
||||
|
||||
pthread_mutex_lock(&sort_param->sort_info->mutex);
|
||||
if (!--sort_param->sort_info->threads_running)
|
||||
pthread_cond_signal(&sort_param->sort_info->cond);
|
||||
pthread_mutex_unlock(&sort_param->sort_info->mutex);
|
||||
|
||||
DBUG_PRINT("exit", ("======== ending thread ========"));
|
||||
my_thread_end();
|
||||
return NULL;
|
||||
}
|
||||
|
@ -469,6 +492,7 @@ int thr_write_keys(MI_SORT_PARAM *sort_param)
|
|||
MYISAM_SHARE *share=info->s;
|
||||
MI_SORT_PARAM *sinfo;
|
||||
byte *mergebuf=0;
|
||||
DBUG_ENTER("thr_write_keys");
|
||||
LINT_INIT(length);
|
||||
|
||||
for (i= 0, sinfo= sort_param ;
|
||||
|
@ -478,6 +502,8 @@ int thr_write_keys(MI_SORT_PARAM *sort_param)
|
|||
if (!sinfo->sort_keys)
|
||||
{
|
||||
got_error=1;
|
||||
my_free(mi_get_rec_buff_ptr(info, sinfo->rec_buff),
|
||||
MYF(MY_ALLOW_ZERO_PTR));
|
||||
continue;
|
||||
}
|
||||
if (!got_error)
|
||||
|
@ -605,7 +631,7 @@ int thr_write_keys(MI_SORT_PARAM *sort_param)
|
|||
}
|
||||
}
|
||||
my_free((gptr) mergebuf,MYF(MY_ALLOW_ZERO_PTR));
|
||||
return got_error;
|
||||
DBUG_RETURN(got_error);
|
||||
}
|
||||
#endif /* THREAD */
|
||||
|
||||
|
|
|
@ -1509,27 +1509,27 @@ i 10
|
|||
select sql_big_result v,count(t) from t1 group by v limit 10;
|
||||
v count(t)
|
||||
a 1
|
||||
a 10
|
||||
b 10
|
||||
c 10
|
||||
d 10
|
||||
e 10
|
||||
f 10
|
||||
g 10
|
||||
h 10
|
||||
i 10
|
||||
a 10
|
||||
b 10
|
||||
c 10
|
||||
d 10
|
||||
e 10
|
||||
f 10
|
||||
g 10
|
||||
h 10
|
||||
i 10
|
||||
select sql_big_result v,count(c) from t1 group by v limit 10;
|
||||
v count(c)
|
||||
a 1
|
||||
a 10
|
||||
b 10
|
||||
c 10
|
||||
d 10
|
||||
e 10
|
||||
f 10
|
||||
g 10
|
||||
h 10
|
||||
i 10
|
||||
a 10
|
||||
b 10
|
||||
c 10
|
||||
d 10
|
||||
e 10
|
||||
f 10
|
||||
g 10
|
||||
h 10
|
||||
i 10
|
||||
select c,count(*) from t1 group by c limit 10;
|
||||
c count(*)
|
||||
a 1
|
||||
|
@ -1673,15 +1673,15 @@ i 10
|
|||
select sql_big_result v,count(t) from t1 group by v limit 10;
|
||||
v count(t)
|
||||
a 1
|
||||
a 10
|
||||
b 10
|
||||
c 10
|
||||
d 10
|
||||
e 10
|
||||
f 10
|
||||
g 10
|
||||
h 10
|
||||
i 10
|
||||
a 10
|
||||
b 10
|
||||
c 10
|
||||
d 10
|
||||
e 10
|
||||
f 10
|
||||
g 10
|
||||
h 10
|
||||
i 10
|
||||
alter table t1 drop key v, add key v (v(30));
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
|
@ -1800,15 +1800,15 @@ i 10
|
|||
select sql_big_result v,count(t) from t1 group by v limit 10;
|
||||
v count(t)
|
||||
a 1
|
||||
a 10
|
||||
b 10
|
||||
c 10
|
||||
d 10
|
||||
e 10
|
||||
f 10
|
||||
g 10
|
||||
h 10
|
||||
i 10
|
||||
a 10
|
||||
b 10
|
||||
c 10
|
||||
d 10
|
||||
e 10
|
||||
f 10
|
||||
g 10
|
||||
h 10
|
||||
i 10
|
||||
drop table t1;
|
||||
create table t1 (a char(10), unique (a));
|
||||
insert into t1 values ('a ');
|
||||
|
|
|
@ -1155,6 +1155,81 @@ check table t1;
|
|||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
drop table t1;
|
||||
set names utf8;
|
||||
create table t1 (s1 char(5) character set utf8);
|
||||
insert into t1 values
|
||||
('a'),('b'),(null),('ペテルグル'),('ü'),('Y');
|
||||
create index it1 on t1 (s1);
|
||||
select s1 as before_delete_general_ci from t1 where s1 like 'ペテ%';
|
||||
before_delete_general_ci
|
||||
ペテルグル
|
||||
delete from t1 where s1 = 'Y';
|
||||
select s1 as after_delete_general_ci from t1 where s1 like 'ペテ%';
|
||||
after_delete_general_ci
|
||||
ペテルグル
|
||||
drop table t1;
|
||||
set names utf8;
|
||||
create table t1 (s1 char(5) character set utf8 collate utf8_unicode_ci);
|
||||
insert into t1 values
|
||||
('a'),('b'),(null),('ペテルグル'),('ü'),('Y');
|
||||
create index it1 on t1 (s1);
|
||||
select s1 as before_delete_unicode_ci from t1 where s1 like 'ペテ%';
|
||||
before_delete_unicode_ci
|
||||
ペテルグル
|
||||
delete from t1 where s1 = 'Y';
|
||||
select s1 as after_delete_unicode_ci from t1 where s1 like 'ペテ%';
|
||||
after_delete_unicode_ci
|
||||
ペテルグル
|
||||
drop table t1;
|
||||
set names utf8;
|
||||
create table t1 (s1 char(5) character set utf8 collate utf8_bin);
|
||||
insert into t1 values
|
||||
('a'),('b'),(null),('ペテルグル'),('ü'),('Y');
|
||||
create index it1 on t1 (s1);
|
||||
select s1 as before_delete_bin from t1 where s1 like 'ペテ%';
|
||||
before_delete_bin
|
||||
ペテルグル
|
||||
delete from t1 where s1 = 'Y';
|
||||
select s1 as after_delete_bin from t1 where s1 like 'ペテ%';
|
||||
after_delete_bin
|
||||
ペテルグル
|
||||
drop table t1;
|
||||
set names utf8;
|
||||
create table t1 (a varchar(30) not null primary key)
|
||||
engine=innodb default character set utf8 collate utf8_general_ci;
|
||||
insert into t1 values ('あいうえおかきくけこさしすせそ');
|
||||
insert into t1 values ('さしすせそかきくけこあいうえお');
|
||||
select a as gci1 from t1 where a like 'さしすせそかきくけこあいうえお%';
|
||||
gci1
|
||||
さしすせそかきくけこあいうえお
|
||||
select a as gci2 from t1 where a like 'あいうえおかきくけこさしすせそ';
|
||||
gci2
|
||||
あいうえおかきくけこさしすせそ
|
||||
drop table t1;
|
||||
set names utf8;
|
||||
create table t1 (a varchar(30) not null primary key)
|
||||
engine=innodb default character set utf8 collate utf8_unicode_ci;
|
||||
insert into t1 values ('あいうえおかきくけこさしすせそ');
|
||||
insert into t1 values ('さしすせそかきくけこあいうえお');
|
||||
select a as uci1 from t1 where a like 'さしすせそかきくけこあいうえお%';
|
||||
uci1
|
||||
さしすせそかきくけこあいうえお
|
||||
select a as uci2 from t1 where a like 'あいうえおかきくけこさしすせそ';
|
||||
uci2
|
||||
あいうえおかきくけこさしすせそ
|
||||
drop table t1;
|
||||
set names utf8;
|
||||
create table t1 (a varchar(30) not null primary key)
|
||||
engine=innodb default character set utf8 collate utf8_bin;
|
||||
insert into t1 values ('あいうえおかきくけこさしすせそ');
|
||||
insert into t1 values ('さしすせそかきくけこあいうえお');
|
||||
select a as bin1 from t1 where a like 'さしすせそかきくけこあいうえお%';
|
||||
bin1
|
||||
さしすせそかきくけこあいうえお
|
||||
select a as bin2 from t1 where a like 'あいうえおかきくけこさしすせそ';
|
||||
bin2
|
||||
あいうえおかきくけこさしすせそ
|
||||
drop table t1;
|
||||
SET NAMES utf8;
|
||||
CREATE TABLE t1 (id int PRIMARY KEY,
|
||||
a varchar(16) collate utf8_unicode_ci NOT NULL default '',
|
||||
|
|
|
@ -74,11 +74,6 @@ grp group_concat(c order by 1)
|
|||
1 a
|
||||
2 b,c
|
||||
3 C,D,d,d,D,E
|
||||
select grp,group_concat(c order by "c") from t1 group by grp;
|
||||
grp group_concat(c order by "c")
|
||||
1 a
|
||||
2 b,c
|
||||
3 C,D,d,d,D,E
|
||||
select grp,group_concat(distinct c order by c) from t1 group by grp;
|
||||
grp group_concat(distinct c order by c)
|
||||
1 a
|
||||
|
|
|
@ -1143,9 +1143,9 @@ EXPLAIN EXTENDED
|
|||
SELECT * FROM t1 INNER JOIN t2 ON code=id
|
||||
WHERE id='a12' AND (LENGTH(code)=5 OR code < 'a00');
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 const PRIMARY PRIMARY 12 const 1 Using index
|
||||
1 SIMPLE t1 ref code code 13 const 3 Using where; Using index
|
||||
1 SIMPLE t2 ref PRIMARY PRIMARY 12 const 1 Using where; Using index
|
||||
Warnings:
|
||||
Note 1003 select `test`.`t1`.`code` AS `code`,`test`.`t2`.`id` AS `id` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`code` = _latin1'a12') and (`test`.`t2`.`id` = _latin1'a12') and (length(`test`.`t1`.`code`) = 5))
|
||||
Note 1003 select `test`.`t1`.`code` AS `code`,`test`.`t2`.`id` AS `id` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`code` = _latin1'a12') and (length(`test`.`t1`.`code`) = 5))
|
||||
DROP TABLE t1,t2;
|
||||
End of 5.0 tests
|
||||
|
|
|
@ -862,3 +862,14 @@ CHECK TABLE t1 EXTENDED;
|
|||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) );
|
||||
INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,1)));
|
||||
INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,0)));
|
||||
INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,1)));
|
||||
INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,0)));
|
||||
SELECT 1 FROM t1 WHERE foo != PointFromWKB(POINT(0,0));
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
DROP TABLE t1;
|
||||
|
|
|
@ -303,10 +303,10 @@ spid sum(userid)
|
|||
1 1
|
||||
explain select sql_big_result score,count(*) from t1 group by score desc;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL score 3 NULL 8 Using index
|
||||
1 SIMPLE t1 index NULL score 3 NULL 8 Using index; Using filesort
|
||||
explain select sql_big_result score,count(*) from t1 group by score desc order by null;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL score 3 NULL 8 Using index
|
||||
1 SIMPLE t1 index NULL score 3 NULL 8 Using index; Using filesort
|
||||
select sql_big_result score,count(*) from t1 group by score desc;
|
||||
score count(*)
|
||||
3 5
|
||||
|
@ -775,6 +775,55 @@ select sql_buffer_result max(f1)+1 from t1;
|
|||
max(f1)+1
|
||||
3
|
||||
drop table t1;
|
||||
CREATE TABLE t1(a INT);
|
||||
INSERT INTO t1 VALUES (1),(2);
|
||||
SELECT a FROM t1 GROUP BY 'a';
|
||||
a
|
||||
1
|
||||
SELECT a FROM t1 GROUP BY "a";
|
||||
a
|
||||
1
|
||||
SELECT a FROM t1 GROUP BY `a`;
|
||||
a
|
||||
1
|
||||
2
|
||||
set sql_mode=ANSI_QUOTES;
|
||||
SELECT a FROM t1 GROUP BY "a";
|
||||
a
|
||||
1
|
||||
2
|
||||
SELECT a FROM t1 GROUP BY 'a';
|
||||
a
|
||||
1
|
||||
SELECT a FROM t1 GROUP BY `a`;
|
||||
a
|
||||
1
|
||||
2
|
||||
set sql_mode='';
|
||||
SELECT a FROM t1 HAVING 'a' > 1;
|
||||
a
|
||||
Warnings:
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'a'
|
||||
SELECT a FROM t1 HAVING "a" > 1;
|
||||
a
|
||||
Warnings:
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'a'
|
||||
SELECT a FROM t1 HAVING `a` > 1;
|
||||
a
|
||||
2
|
||||
SELECT a FROM t1 ORDER BY 'a' DESC;
|
||||
a
|
||||
1
|
||||
2
|
||||
SELECT a FROM t1 ORDER BY "a" DESC;
|
||||
a
|
||||
1
|
||||
2
|
||||
SELECT a FROM t1 ORDER BY `a` DESC;
|
||||
a
|
||||
2
|
||||
1
|
||||
DROP TABLE t1;
|
||||
create table t1 (c1 char(3), c2 char(3));
|
||||
create table t2 (c3 char(3), c4 char(3));
|
||||
insert into t1 values ('aaa', 'bb1'), ('aaa', 'bb2');
|
||||
|
@ -821,3 +870,66 @@ a b real_b
|
|||
68 France France
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1,t2;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY, b INT, key (b));
|
||||
INSERT INTO t1 VALUES (1, 1);
|
||||
INSERT INTO t1 SELECT a + 1 , MOD(a + 1 , 20) FROM t1;
|
||||
INSERT INTO t1 SELECT a + 2 , MOD(a + 2 , 20) FROM t1;
|
||||
INSERT INTO t1 SELECT a + 4 , MOD(a + 4 , 20) FROM t1;
|
||||
INSERT INTO t1 SELECT a + 8 , MOD(a + 8 , 20) FROM t1;
|
||||
INSERT INTO t1 SELECT a + 16, MOD(a + 16, 20) FROM t1;
|
||||
INSERT INTO t1 SELECT a + 32, MOD(a + 32, 20) FROM t1;
|
||||
INSERT INTO t1 SELECT a + 64, MOD(a + 64, 20) FROM t1;
|
||||
SELECT MIN(b), MAX(b) from t1;
|
||||
MIN(b) MAX(b)
|
||||
0 19
|
||||
EXPLAIN SELECT b, sum(1) FROM t1 GROUP BY b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL b 5 NULL 128 Using index
|
||||
EXPLAIN SELECT SQL_BIG_RESULT b, sum(1) FROM t1 GROUP BY b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL b 5 NULL 128 Using index; Using filesort
|
||||
SELECT b, sum(1) FROM t1 GROUP BY b;
|
||||
b sum(1)
|
||||
0 6
|
||||
1 7
|
||||
2 7
|
||||
3 7
|
||||
4 7
|
||||
5 7
|
||||
6 7
|
||||
7 7
|
||||
8 7
|
||||
9 6
|
||||
10 6
|
||||
11 6
|
||||
12 6
|
||||
13 6
|
||||
14 6
|
||||
15 6
|
||||
16 6
|
||||
17 6
|
||||
18 6
|
||||
19 6
|
||||
SELECT SQL_BIG_RESULT b, sum(1) FROM t1 GROUP BY b;
|
||||
b sum(1)
|
||||
0 6
|
||||
1 7
|
||||
2 7
|
||||
3 7
|
||||
4 7
|
||||
5 7
|
||||
6 7
|
||||
7 7
|
||||
8 7
|
||||
9 6
|
||||
10 6
|
||||
11 6
|
||||
12 6
|
||||
13 6
|
||||
14 6
|
||||
15 6
|
||||
16 6
|
||||
17 6
|
||||
18 6
|
||||
19 6
|
||||
DROP TABLE t1;
|
||||
|
|
|
@ -2142,3 +2142,23 @@ t1;
|
|||
id2 id3 id5 id4 id3 id6 id5 id1
|
||||
1 1 1 1 1 1 1 1
|
||||
DROP TABLE t1,t2,t3,t4,t5,t6;
|
||||
CREATE TABLE t1 (a int, b int, PRIMARY KEY (a,b), KEY b (b));
|
||||
INSERT INTO t1 VALUES (1,1),(1,2),(1,0),(1,3);
|
||||
explain SELECT MAX(b), a FROM t1 WHERE b < 2 AND a = 1 GROUP BY a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range PRIMARY,b PRIMARY 8 NULL 1 Using where; Using index for group-by
|
||||
SELECT MAX(b), a FROM t1 WHERE b < 2 AND a = 1 GROUP BY a;
|
||||
MAX(b) a
|
||||
1 1
|
||||
SELECT MIN(b), a FROM t1 WHERE b > 1 AND a = 1 GROUP BY a;
|
||||
MIN(b) a
|
||||
2 1
|
||||
CREATE TABLE t2 (a int, b int, c int, PRIMARY KEY (a,b,c));
|
||||
INSERT INTO t2 SELECT a,b,b FROM t1;
|
||||
explain SELECT MIN(c) FROM t2 WHERE b = 2 and a = 1 and c > 1 GROUP BY a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 range PRIMARY PRIMARY 12 NULL 1 Using where; Using index for group-by
|
||||
SELECT MIN(c) FROM t2 WHERE b = 2 and a = 1 and c > 1 GROUP BY a;
|
||||
MIN(c)
|
||||
2
|
||||
DROP TABLE t1,t2;
|
||||
|
|
|
@ -2070,15 +2070,15 @@ i 10
|
|||
select sql_big_result v,count(c) from t1 group by v limit 10;
|
||||
v count(c)
|
||||
a 1
|
||||
a 10
|
||||
b 10
|
||||
c 10
|
||||
d 10
|
||||
e 10
|
||||
f 10
|
||||
g 10
|
||||
a 10
|
||||
b 10
|
||||
c 10
|
||||
d 10
|
||||
e 10
|
||||
f 10
|
||||
g 10
|
||||
h 10
|
||||
i 10
|
||||
i 10
|
||||
select c,count(*) from t1 group by c limit 10;
|
||||
c count(*)
|
||||
a 1
|
||||
|
|
|
@ -353,3 +353,20 @@ Warnings:
|
|||
Warning 1071 Specified key was too long; max key length is 765 bytes
|
||||
insert into t1 values('aaa');
|
||||
drop table t1;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c FLOAT, KEY b(b)) ENGINE = INNODB;
|
||||
INSERT INTO t1 VALUES ( 1 , 1 , 1);
|
||||
INSERT INTO t1 SELECT a + 1 , MOD(a + 1 , 20), 1 FROM t1;
|
||||
INSERT INTO t1 SELECT a + 2 , MOD(a + 2 , 20), 1 FROM t1;
|
||||
INSERT INTO t1 SELECT a + 4 , MOD(a + 4 , 20), 1 FROM t1;
|
||||
INSERT INTO t1 SELECT a + 8 , MOD(a + 8 , 20), 1 FROM t1;
|
||||
INSERT INTO t1 SELECT a + 16, MOD(a + 16, 20), 1 FROM t1;
|
||||
INSERT INTO t1 SELECT a + 32, MOD(a + 32, 20), 1 FROM t1;
|
||||
INSERT INTO t1 SELECT a + 64, MOD(a + 64, 20), 1 FROM t1;
|
||||
EXPLAIN SELECT b, SUM(c) FROM t1 GROUP BY b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL b 5 NULL 128
|
||||
EXPLAIN SELECT SQL_BIG_RESULT b, SUM(c) FROM t1 GROUP BY b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 128 Using filesort
|
||||
DROP TABLE t1;
|
||||
End of 5.0 tests
|
||||
|
|
|
@ -626,7 +626,7 @@ id select_type table type possible_keys key key_len ref rows Extra
|
|||
EXPLAIN SELECT * FROM t2 WHERE fileset_id = 2
|
||||
AND file_code = '0000000115' LIMIT 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ref PRIMARY,files PRIMARY 35 const,const 1 Using where
|
||||
1 SIMPLE t2 const PRIMARY,files PRIMARY 35 const,const 1
|
||||
DROP TABLE t2, t1;
|
||||
create table t1 (x int, y int, index xy(x, y));
|
||||
create table t2 (x int, y int, index xy(x, y));
|
||||
|
|
|
@ -796,6 +796,132 @@ a b
|
|||
xxxxxxxxx bbbbbb
|
||||
xxxxxxxxx bbbbbb
|
||||
DROP TABLE t1;
|
||||
SET @@myisam_repair_threads=2;
|
||||
SHOW VARIABLES LIKE 'myisam_repair%';
|
||||
Variable_name Value
|
||||
myisam_repair_threads 2
|
||||
CREATE TABLE t1 (
|
||||
`_id` int(11) NOT NULL default '0',
|
||||
`url` text,
|
||||
`email` text,
|
||||
`description` text,
|
||||
`loverlap` int(11) default NULL,
|
||||
`roverlap` int(11) default NULL,
|
||||
`lneighbor_id` int(11) default NULL,
|
||||
`rneighbor_id` int(11) default NULL,
|
||||
`length_` int(11) default NULL,
|
||||
`sequence` mediumtext,
|
||||
`name` text,
|
||||
`_obj_class` text NOT NULL,
|
||||
PRIMARY KEY (`_id`),
|
||||
UNIQUE KEY `sequence_name_index` (`name`(50)),
|
||||
KEY (`length_`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
||||
INSERT INTO t1 VALUES
|
||||
(1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample1',''),
|
||||
(2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample2',''),
|
||||
(3,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample3',''),
|
||||
(4,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample4',''),
|
||||
(5,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample5',''),
|
||||
(6,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample6',''),
|
||||
(7,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample7',''),
|
||||
(8,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample8',''),
|
||||
(9,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample9','');
|
||||
SELECT _id FROM t1;
|
||||
_id
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
DELETE FROM t1 WHERE _id < 8;
|
||||
SHOW TABLE STATUS LIKE 't1';
|
||||
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
|
||||
t1 MyISAM 10 Dynamic 2 # # # # 140 # # # # # #
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
OPTIMIZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 optimize status OK
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
SHOW TABLE STATUS LIKE 't1';
|
||||
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
|
||||
t1 MyISAM 10 Dynamic 2 # # # # 0 # # # # # #
|
||||
SELECT _id FROM t1;
|
||||
_id
|
||||
8
|
||||
9
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (
|
||||
`_id` int(11) NOT NULL default '0',
|
||||
`url` text,
|
||||
`email` text,
|
||||
`description` text,
|
||||
`loverlap` int(11) default NULL,
|
||||
`roverlap` int(11) default NULL,
|
||||
`lneighbor_id` int(11) default NULL,
|
||||
`rneighbor_id` int(11) default NULL,
|
||||
`length_` int(11) default NULL,
|
||||
`sequence` mediumtext,
|
||||
`name` text,
|
||||
`_obj_class` text NOT NULL,
|
||||
PRIMARY KEY (`_id`),
|
||||
UNIQUE KEY `sequence_name_index` (`name`(50)),
|
||||
KEY (`length_`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
||||
INSERT INTO t1 VALUES
|
||||
(1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample1',''),
|
||||
(2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample2',''),
|
||||
(3,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample3',''),
|
||||
(4,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample4',''),
|
||||
(5,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample5',''),
|
||||
(6,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample6',''),
|
||||
(7,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample7',''),
|
||||
(8,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample8',''),
|
||||
(9,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample9','');
|
||||
SELECT _id FROM t1;
|
||||
_id
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
DELETE FROM t1 WHERE _id < 8;
|
||||
SHOW TABLE STATUS LIKE 't1';
|
||||
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
|
||||
t1 MyISAM 10 Dynamic 2 # # # # 140 # # # # # #
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
REPAIR TABLE t1 QUICK;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair status OK
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
SHOW TABLE STATUS LIKE 't1';
|
||||
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
|
||||
t1 MyISAM 10 Dynamic 2 # # # # 140 # # # # # #
|
||||
SELECT _id FROM t1;
|
||||
_id
|
||||
8
|
||||
9
|
||||
DROP TABLE t1;
|
||||
SET @@myisam_repair_threads=1;
|
||||
SHOW VARIABLES LIKE 'myisam_repair%';
|
||||
Variable_name Value
|
||||
myisam_repair_threads 1
|
||||
set storage_engine=MyISAM;
|
||||
drop table if exists t1,t2,t3;
|
||||
--- Testing varchar ---
|
||||
|
@ -1002,15 +1128,15 @@ i 10
|
|||
select sql_big_result v,count(c) from t1 group by v limit 10;
|
||||
v count(c)
|
||||
a 1
|
||||
a 10
|
||||
b 10
|
||||
c 10
|
||||
d 10
|
||||
e 10
|
||||
f 10
|
||||
g 10
|
||||
a 10
|
||||
b 10
|
||||
c 10
|
||||
d 10
|
||||
e 10
|
||||
f 10
|
||||
g 10
|
||||
h 10
|
||||
i 10
|
||||
i 10
|
||||
select c,count(*) from t1 group by c limit 10;
|
||||
c count(*)
|
||||
a 1
|
||||
|
|
|
@ -592,6 +592,21 @@ a max(b)
|
|||
NULL 2
|
||||
a 1
|
||||
drop table t1;
|
||||
create table t1 (a varchar(22) not null , b int);
|
||||
insert into t1 values ("2006-07-01 21:30", 1), ("2006-07-01 23:30", 10);
|
||||
select left(a,10), a, sum(b) from t1 group by 1,2 with rollup;
|
||||
left(a,10) a sum(b)
|
||||
2006-07-01 2006-07-01 21:30 1
|
||||
2006-07-01 2006-07-01 23:30 10
|
||||
2006-07-01 NULL 11
|
||||
NULL NULL 11
|
||||
select left(a,10) x, a, sum(b) from t1 group by x,a with rollup;
|
||||
x a sum(b)
|
||||
2006-07-01 2006-07-01 21:30 1
|
||||
2006-07-01 2006-07-01 23:30 10
|
||||
2006-07-01 NULL 11
|
||||
NULL NULL 11
|
||||
drop table t1;
|
||||
CREATE TABLE t1(id int, type char(1));
|
||||
INSERT INTO t1 VALUES
|
||||
(1,"A"),(2,"C"),(3,"A"),(4,"A"),(5,"B"),
|
||||
|
|
|
@ -54,3 +54,13 @@ Tables_in_test
|
|||
t2
|
||||
t4
|
||||
drop table t2, t4;
|
||||
create table t1(f1 int);
|
||||
create view v1 as select * from t1;
|
||||
alter table v1 rename to v2;
|
||||
alter table v1 rename to v2;
|
||||
ERROR 42S02: Table 'test.v1' doesn't exist
|
||||
rename table v2 to v1;
|
||||
rename table v2 to v1;
|
||||
ERROR 42S01: Table 'v1' already exists
|
||||
drop view v1;
|
||||
drop table t1;
|
||||
|
|
|
@ -52,3 +52,41 @@ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_par
|
|||
t1 1 a 1 a A 5 NULL NULL YES BTREE
|
||||
SET myisam_repair_threads=@@global.myisam_repair_threads;
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(a INT);
|
||||
USE mysql;
|
||||
REPAIR TABLE test.t1 USE_FRM;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair status OK
|
||||
USE test;
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(a CHAR(255), KEY(a));
|
||||
SET myisam_sort_buffer_size=4096;
|
||||
INSERT INTO t1 VALUES
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0');
|
||||
Warnings:
|
||||
Error 1034 sort_buffer_size is to small
|
||||
Error 1034 Number of rows changed from 0 to 157
|
||||
SET myisam_repair_threads=2;
|
||||
REPAIR TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair error sort_buffer_size is to small
|
||||
test.t1 repair warning Number of rows changed from 0 to 157
|
||||
test.t1 repair status OK
|
||||
SET myisam_repair_threads=@@global.myisam_repair_threads;
|
||||
SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size;
|
||||
DROP TABLE t1;
|
||||
|
|
|
@ -3517,3 +3517,97 @@ id a b c d e
|
|||
2 NULL NULL NULL 2 40
|
||||
2 NULL NULL NULL 2 50
|
||||
DROP TABLE t1,t2,t3;
|
||||
create table t1 (c1 varchar(1), c2 int, c3 int, c4 int, c5 int, c6 int,
|
||||
c7 int, c8 int, c9 int, fulltext key (`c1`));
|
||||
select distinct match (`c1`) against ('z') , c2, c3, c4,c5, c6,c7, c8
|
||||
from t1 where c9=1 order by c2, c2;
|
||||
match (`c1`) against ('z') c2 c3 c4 c5 c6 c7 c8
|
||||
drop table t1;
|
||||
CREATE TABLE t1 (pk varchar(10) PRIMARY KEY, fk varchar(16));
|
||||
CREATE TABLE t2 (pk varchar(16) PRIMARY KEY, fk varchar(10));
|
||||
INSERT INTO t1 VALUES
|
||||
('d','dddd'), ('i','iii'), ('a','aa'), ('b','bb'), ('g','gg'),
|
||||
('e','eee'), ('c','cccc'), ('h','hhh'), ('j','jjj'), ('f','fff');
|
||||
INSERT INTO t2 VALUES
|
||||
('jjj', 'j'), ('cc','c'), ('ccc','c'), ('aaa', 'a'), ('jjjj','j'),
|
||||
('hhh','h'), ('gg','g'), ('fff','f'), ('ee','e'), ('ffff','f'),
|
||||
('bbb','b'), ('ff','f'), ('cccc','c'), ('dddd','d'), ('jj','j'),
|
||||
('aaaa','a'), ('bb','b'), ('eeee','e'), ('aa','a'), ('hh','h');
|
||||
EXPLAIN SELECT t2.*
|
||||
FROM t1 JOIN t2 ON t2.fk=t1.pk
|
||||
WHERE t2.fk < 'c' AND t2.pk=t1.fk;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 3 Using where
|
||||
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where
|
||||
EXPLAIN SELECT t2.*
|
||||
FROM t1 JOIN t2 ON t2.fk=t1.pk
|
||||
WHERE t2.fk BETWEEN 'a' AND 'b' AND t2.pk=t1.fk;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using where
|
||||
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where
|
||||
EXPLAIN SELECT t2.*
|
||||
FROM t1 JOIN t2 ON t2.fk=t1.pk
|
||||
WHERE t2.fk IN ('a','b') AND t2.pk=t1.fk;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using where
|
||||
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where
|
||||
DROP TABLE t1,t2;
|
||||
CREATE TABLE t1 (a int, b varchar(20) NOT NULL, PRIMARY KEY(a));
|
||||
CREATE TABLE t2 (a int, b varchar(20) NOT NULL,
|
||||
PRIMARY KEY (a), UNIQUE KEY (b));
|
||||
INSERT INTO t1 VALUES (1,'a'),(2,'b'),(3,'c');
|
||||
INSERT INTO t2 VALUES (1,'a'),(2,'b'),(3,'c');
|
||||
EXPLAIN SELECT t1.a FROM t1 LEFT JOIN t2 ON t2.b=t1.b WHERE t1.a=3;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
|
||||
1 SIMPLE t2 const b b 22 const 1 Using index
|
||||
DROP TABLE t1,t2;
|
||||
CREATE TABLE t1(id int PRIMARY KEY, b int, e int);
|
||||
CREATE TABLE t2(i int, a int, INDEX si(i), INDEX ai(a));
|
||||
CREATE TABLE t3(a int PRIMARY KEY, c char(4), INDEX ci(c));
|
||||
INSERT INTO t1 VALUES
|
||||
(1,10,19), (2,20,22), (4,41,42), (9,93,95), (7, 77,79),
|
||||
(6,63,67), (5,55,58), (3,38,39), (8,81,89);
|
||||
INSERT INTO t2 VALUES
|
||||
(21,210), (41,410), (82,820), (83,830), (84,840),
|
||||
(65,650), (51,510), (37,370), (94,940), (76,760),
|
||||
(22,220), (33,330), (40,400), (95,950), (38,380),
|
||||
(67,670), (88,880), (57,570), (96,960), (97,970);
|
||||
INSERT INTO t3 VALUES
|
||||
(210,'bb'), (950,'ii'), (400,'ab'), (500,'ee'), (220,'gg'),
|
||||
(440,'gg'), (310,'eg'), (380,'ee'), (840,'bb'), (830,'ff'),
|
||||
(230,'aa'), (960,'ii'), (410,'aa'), (510,'ee'), (290,'bb'),
|
||||
(450,'gg'), (320,'dd'), (390,'hh'), (850,'jj'), (860,'ff');
|
||||
EXPLAIN
|
||||
SELECT t3.a FROM t1,t2 FORCE INDEX (si),t3
|
||||
WHERE t1.id = 8 AND t2.i BETWEEN t1.b AND t1.e AND
|
||||
t3.a=t2.a AND t3.c IN ('bb','ee');
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
|
||||
1 SIMPLE t2 range si si 5 NULL 4 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where
|
||||
EXPLAIN
|
||||
SELECT t3.a FROM t1,t2,t3
|
||||
WHERE t1.id = 8 AND t2.i BETWEEN t1.b AND t1.e AND
|
||||
t3.a=t2.a AND t3.c IN ('bb','ee') ;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
|
||||
1 SIMPLE t2 range si,ai si 5 NULL 4 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where
|
||||
EXPLAIN
|
||||
SELECT t3.a FROM t1,t2 FORCE INDEX (si),t3
|
||||
WHERE t1.id = 8 AND (t2.i=t1.b OR t2.i=t1.e) AND t3.a=t2.a AND
|
||||
t3.c IN ('bb','ee');
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
|
||||
1 SIMPLE t2 range si si 5 NULL 2 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where
|
||||
EXPLAIN
|
||||
SELECT t3.a FROM t1,t2,t3
|
||||
WHERE t1.id = 8 AND (t2.i=t1.b OR t2.i=t1.e) AND t3.a=t2.a AND
|
||||
t3.c IN ('bb','ee');
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
|
||||
1 SIMPLE t2 range si,ai si 5 NULL 2 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where
|
||||
DROP TABLE t1,t2,t3;
|
||||
|
|
|
@ -363,12 +363,12 @@ INSERT INTO t8 (pseudo,email) VALUES ('joce1','test1');
|
|||
INSERT INTO t8 (pseudo,email) VALUES ('2joce1','2test1');
|
||||
EXPLAIN EXTENDED SELECT pseudo,(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce')) FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce');
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t8 ref PRIMARY PRIMARY 37 const 1 Using where; Using index
|
||||
4 SUBQUERY t8 ref PRIMARY PRIMARY 37 1 Using where; Using index
|
||||
2 SUBQUERY t8 ref PRIMARY PRIMARY 37 const 1 Using where
|
||||
3 SUBQUERY t8 ref PRIMARY PRIMARY 37 1 Using where; Using index
|
||||
1 PRIMARY t8 const PRIMARY PRIMARY 37 const 1 Using index
|
||||
4 SUBQUERY t8 const PRIMARY PRIMARY 37 1 Using index
|
||||
2 SUBQUERY t8 const PRIMARY PRIMARY 37 const 1
|
||||
3 SUBQUERY t8 const PRIMARY PRIMARY 37 1 Using index
|
||||
Warnings:
|
||||
Note 1003 select `test`.`t8`.`pseudo` AS `pseudo`,(select `test`.`t8`.`email` AS `email` from `test`.`t8` where (`test`.`t8`.`pseudo` = (select `test`.`t8`.`pseudo` AS `pseudo` from `test`.`t8` where (`test`.`t8`.`pseudo` = _latin1'joce')))) AS `(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'))` from `test`.`t8` where (`test`.`t8`.`pseudo` = (select `test`.`t8`.`pseudo` AS `pseudo` from `test`.`t8` where (`test`.`t8`.`pseudo` = _latin1'joce')))
|
||||
Note 1003 select `test`.`t8`.`pseudo` AS `pseudo`,(select `test`.`t8`.`email` AS `email` from `test`.`t8` where 1) AS `(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'))` from `test`.`t8` where 1
|
||||
SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo,email FROM
|
||||
t8 WHERE pseudo='joce');
|
||||
ERROR 21000: Operand should contain 1 column(s)
|
||||
|
@ -3457,6 +3457,32 @@ id select_type table type possible_keys key key_len ref rows Extra
|
|||
4 UNION t12 system NULL NULL NULL NULL 0 const row not found
|
||||
NULL UNION RESULT <union2,4> ALL NULL NULL NULL NULL NULL
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (a VARCHAR(250), b INT auto_increment, PRIMARY KEY (b));
|
||||
insert into t1 (a) values (FLOOR(rand() * 100));
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
SELECT a,
|
||||
(SELECT REPEAT(' ',250) FROM t1 i1
|
||||
WHERE i1.b=t1.a ORDER BY RAND() LIMIT 1) AS a
|
||||
FROM t1 ORDER BY a LIMIT 5;
|
||||
a a
|
||||
0 NULL
|
||||
0 NULL
|
||||
0 NULL
|
||||
0 NULL
|
||||
0 NULL
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (a INT, b INT);
|
||||
CREATE TABLE t2 (a INT);
|
||||
INSERT INTO t2 values (1);
|
||||
|
|
|
@ -779,3 +779,14 @@ select f1 from t1 where f1 in (select f1 from t1);
|
|||
f1
|
||||
40
|
||||
drop table t1;
|
||||
create table t1 as
|
||||
select from_days(s) as date,t
|
||||
from (select 1 as s,'t' as t union select null, null ) as sub1;
|
||||
select group_concat(t) from t1 group by week(date)/10;
|
||||
group_concat(t)
|
||||
t
|
||||
Warnings:
|
||||
Warning 1292 Truncated incorrect datetime value: '0000-00-00'
|
||||
Warning 1292 Truncated incorrect datetime value: '0000-00-00'
|
||||
Warning 1292 Truncated incorrect datetime value: '0000-00-00'
|
||||
drop table t1;
|
||||
|
|
|
@ -1745,3 +1745,12 @@ create table t1 (a set('x','y') default 'x');
|
|||
alter table t1 alter a set default 'z';
|
||||
ERROR 42000: Invalid default value for 'a'
|
||||
drop table t1;
|
||||
create table t1 (f1 int);
|
||||
alter table t1 add f2 enum(0xFFFF);
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`f1` int(11) default NULL,
|
||||
`f2` enum('ÿÿ') default NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
drop table t1;
|
||||
|
|
|
@ -2956,4 +2956,14 @@ View Create View
|
|||
v1 CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`pk` AS `pk` from (`t1` join `t2` on(((`t2`.`fk` = `t1`.`pk`) and (`t2`.`ver` = (select max(`t`.`ver`) AS `MAX(t.ver)` from `t2` `t` where (`t`.`org` = `t2`.`org`))))))
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1, t2;
|
||||
CREATE TABLE t1(id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, val INT UNSIGNED NOT NULL);
|
||||
CREATE VIEW v1 AS SELECT id, val FROM t1 WHERE val >= 1 AND val <= 5 WITH CHECK OPTION;
|
||||
INSERT INTO v1 (val) VALUES (2);
|
||||
INSERT INTO v1 (val) VALUES (4);
|
||||
INSERT INTO v1 (val) VALUES (6);
|
||||
ERROR HY000: CHECK OPTION failed 'test.v1'
|
||||
UPDATE v1 SET val=6 WHERE id=2;
|
||||
ERROR HY000: CHECK OPTION failed 'test.v1'
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1;
|
||||
End of 5.0 tests.
|
||||
|
|
|
@ -941,6 +941,76 @@ INSERT INTO t1 VALUES('uUABCDEFGHIGKLMNOPRSTUVWXYZ̈bbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
|||
check table t1;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Bug#20471 LIKE search fails with indexed utf8 char column
|
||||
#
|
||||
set names utf8;
|
||||
create table t1 (s1 char(5) character set utf8);
|
||||
insert into t1 values
|
||||
('a'),('b'),(null),('ペテルグル'),('ü'),('Y');
|
||||
create index it1 on t1 (s1);
|
||||
select s1 as before_delete_general_ci from t1 where s1 like 'ペテ%';
|
||||
delete from t1 where s1 = 'Y';
|
||||
select s1 as after_delete_general_ci from t1 where s1 like 'ペテ%';
|
||||
drop table t1;
|
||||
|
||||
set names utf8;
|
||||
create table t1 (s1 char(5) character set utf8 collate utf8_unicode_ci);
|
||||
insert into t1 values
|
||||
('a'),('b'),(null),('ペテルグル'),('ü'),('Y');
|
||||
create index it1 on t1 (s1);
|
||||
select s1 as before_delete_unicode_ci from t1 where s1 like 'ペテ%';
|
||||
delete from t1 where s1 = 'Y';
|
||||
select s1 as after_delete_unicode_ci from t1 where s1 like 'ペテ%';
|
||||
drop table t1;
|
||||
|
||||
set names utf8;
|
||||
create table t1 (s1 char(5) character set utf8 collate utf8_bin);
|
||||
insert into t1 values
|
||||
('a'),('b'),(null),('ペテルグル'),('ü'),('Y');
|
||||
create index it1 on t1 (s1);
|
||||
select s1 as before_delete_bin from t1 where s1 like 'ペテ%';
|
||||
delete from t1 where s1 = 'Y';
|
||||
select s1 as after_delete_bin from t1 where s1 like 'ペテ%';
|
||||
drop table t1;
|
||||
|
||||
# additional tests from duplicate bug#20744 MySQL return no result
|
||||
|
||||
set names utf8;
|
||||
--disable_warnings
|
||||
create table t1 (a varchar(30) not null primary key)
|
||||
engine=innodb default character set utf8 collate utf8_general_ci;
|
||||
--enable_warnings
|
||||
insert into t1 values ('あいうえおかきくけこさしすせそ');
|
||||
insert into t1 values ('さしすせそかきくけこあいうえお');
|
||||
select a as gci1 from t1 where a like 'さしすせそかきくけこあいうえお%';
|
||||
select a as gci2 from t1 where a like 'あいうえおかきくけこさしすせそ';
|
||||
drop table t1;
|
||||
|
||||
set names utf8;
|
||||
--disable_warnings
|
||||
create table t1 (a varchar(30) not null primary key)
|
||||
engine=innodb default character set utf8 collate utf8_unicode_ci;
|
||||
--enable_warnings
|
||||
insert into t1 values ('あいうえおかきくけこさしすせそ');
|
||||
insert into t1 values ('さしすせそかきくけこあいうえお');
|
||||
select a as uci1 from t1 where a like 'さしすせそかきくけこあいうえお%';
|
||||
select a as uci2 from t1 where a like 'あいうえおかきくけこさしすせそ';
|
||||
drop table t1;
|
||||
|
||||
set names utf8;
|
||||
--disable_warnings
|
||||
create table t1 (a varchar(30) not null primary key)
|
||||
engine=innodb default character set utf8 collate utf8_bin;
|
||||
--enable_warnings
|
||||
insert into t1 values ('あいうえおかきくけこさしすせそ');
|
||||
insert into t1 values ('さしすせそかきくけこあいうえお');
|
||||
select a as bin1 from t1 where a like 'さしすせそかきくけこあいうえお%';
|
||||
select a as bin2 from t1 where a like 'あいうえおかきくけこさしすせそ';
|
||||
drop table t1;
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Bug#14896: Comparison with a key in a partial index over mb chararacter field
|
||||
#
|
||||
|
|
|
@ -32,7 +32,6 @@ select grp,group_concat(d order by a desc) from t1 group by grp;
|
|||
select grp,group_concat(a order by a,d+c-ascii(c)-a) from t1 group by grp;
|
||||
select grp,group_concat(a order by d+c-ascii(c),a) from t1 group by grp;
|
||||
select grp,group_concat(c order by 1) from t1 group by grp;
|
||||
select grp,group_concat(c order by "c") from t1 group by grp;
|
||||
select grp,group_concat(distinct c order by c) from t1 group by grp;
|
||||
select grp,group_concat(distinct c order by c desc) from t1 group by grp;
|
||||
explain extended select grp,group_concat(distinct c order by c desc) from t1 group by grp;
|
||||
|
|
|
@ -231,4 +231,14 @@ INSERT INTO t1 (c1) VALUES (
|
|||
CHECK TABLE t1 EXTENDED;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# Bug #21888: Query on GEOMETRY field using PointFromWKB() results in lost connection
|
||||
#
|
||||
CREATE TABLE t1 (foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) );
|
||||
INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,1)));
|
||||
INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,0)));
|
||||
INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,1)));
|
||||
INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,0)));
|
||||
SELECT 1 FROM t1 WHERE foo != PointFromWKB(POINT(0,0));
|
||||
DROP TABLE t1;
|
||||
# End of 4.1 tests
|
||||
|
|
|
@ -609,6 +609,30 @@ select sql_buffer_result max(f1) is null from t1;
|
|||
select sql_buffer_result max(f1)+1 from t1;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# BUG#14019-4.1-opt
|
||||
#
|
||||
CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (1),(2);
|
||||
|
||||
SELECT a FROM t1 GROUP BY 'a';
|
||||
SELECT a FROM t1 GROUP BY "a";
|
||||
SELECT a FROM t1 GROUP BY `a`;
|
||||
|
||||
set sql_mode=ANSI_QUOTES;
|
||||
SELECT a FROM t1 GROUP BY "a";
|
||||
SELECT a FROM t1 GROUP BY 'a';
|
||||
SELECT a FROM t1 GROUP BY `a`;
|
||||
set sql_mode='';
|
||||
|
||||
SELECT a FROM t1 HAVING 'a' > 1;
|
||||
SELECT a FROM t1 HAVING "a" > 1;
|
||||
SELECT a FROM t1 HAVING `a` > 1;
|
||||
|
||||
SELECT a FROM t1 ORDER BY 'a' DESC;
|
||||
SELECT a FROM t1 ORDER BY "a" DESC;
|
||||
SELECT a FROM t1 ORDER BY `a` DESC;
|
||||
DROP TABLE t1;
|
||||
|
||||
# End of 4.1 tests
|
||||
|
||||
#
|
||||
|
@ -655,3 +679,25 @@ where t2.b=v1.a GROUP BY t2.b;
|
|||
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
#
|
||||
# Bug#22781: SQL_BIG_RESULT fails to influence sort plan
|
||||
#
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY, b INT, key (b));
|
||||
|
||||
INSERT INTO t1 VALUES (1, 1);
|
||||
INSERT INTO t1 SELECT a + 1 , MOD(a + 1 , 20) FROM t1;
|
||||
INSERT INTO t1 SELECT a + 2 , MOD(a + 2 , 20) FROM t1;
|
||||
INSERT INTO t1 SELECT a + 4 , MOD(a + 4 , 20) FROM t1;
|
||||
INSERT INTO t1 SELECT a + 8 , MOD(a + 8 , 20) FROM t1;
|
||||
INSERT INTO t1 SELECT a + 16, MOD(a + 16, 20) FROM t1;
|
||||
INSERT INTO t1 SELECT a + 32, MOD(a + 32, 20) FROM t1;
|
||||
INSERT INTO t1 SELECT a + 64, MOD(a + 64, 20) FROM t1;
|
||||
|
||||
SELECT MIN(b), MAX(b) from t1;
|
||||
|
||||
EXPLAIN SELECT b, sum(1) FROM t1 GROUP BY b;
|
||||
EXPLAIN SELECT SQL_BIG_RESULT b, sum(1) FROM t1 GROUP BY b;
|
||||
SELECT b, sum(1) FROM t1 GROUP BY b;
|
||||
SELECT SQL_BIG_RESULT b, sum(1) FROM t1 GROUP BY b;
|
||||
DROP TABLE t1;
|
||||
|
|
|
@ -794,3 +794,19 @@ SELECT * FROM
|
|||
t1;
|
||||
|
||||
DROP TABLE t1,t2,t3,t4,t5,t6;
|
||||
|
||||
#
|
||||
# Bug#22342: No results returned for query using max and group by
|
||||
#
|
||||
CREATE TABLE t1 (a int, b int, PRIMARY KEY (a,b), KEY b (b));
|
||||
INSERT INTO t1 VALUES (1,1),(1,2),(1,0),(1,3);
|
||||
|
||||
explain SELECT MAX(b), a FROM t1 WHERE b < 2 AND a = 1 GROUP BY a;
|
||||
SELECT MAX(b), a FROM t1 WHERE b < 2 AND a = 1 GROUP BY a;
|
||||
SELECT MIN(b), a FROM t1 WHERE b > 1 AND a = 1 GROUP BY a;
|
||||
CREATE TABLE t2 (a int, b int, c int, PRIMARY KEY (a,b,c));
|
||||
INSERT INTO t2 SELECT a,b,b FROM t1;
|
||||
explain SELECT MIN(c) FROM t2 WHERE b = 2 and a = 1 and c > 1 GROUP BY a;
|
||||
SELECT MIN(c) FROM t2 WHERE b = 2 and a = 1 and c > 1 GROUP BY a;
|
||||
|
||||
DROP TABLE t1,t2;
|
||||
|
|
|
@ -326,3 +326,25 @@ create table t1(f1 varchar(800) binary not null, key(f1)) engine = innodb
|
|||
character set utf8 collate utf8_general_ci;
|
||||
insert into t1 values('aaa');
|
||||
drop table t1;
|
||||
|
||||
|
||||
#
|
||||
# Bug#22781: SQL_BIG_RESULT fails to influence sort plan
|
||||
#
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c FLOAT, KEY b(b)) ENGINE = INNODB;
|
||||
|
||||
INSERT INTO t1 VALUES ( 1 , 1 , 1);
|
||||
INSERT INTO t1 SELECT a + 1 , MOD(a + 1 , 20), 1 FROM t1;
|
||||
INSERT INTO t1 SELECT a + 2 , MOD(a + 2 , 20), 1 FROM t1;
|
||||
INSERT INTO t1 SELECT a + 4 , MOD(a + 4 , 20), 1 FROM t1;
|
||||
INSERT INTO t1 SELECT a + 8 , MOD(a + 8 , 20), 1 FROM t1;
|
||||
INSERT INTO t1 SELECT a + 16, MOD(a + 16, 20), 1 FROM t1;
|
||||
INSERT INTO t1 SELECT a + 32, MOD(a + 32, 20), 1 FROM t1;
|
||||
INSERT INTO t1 SELECT a + 64, MOD(a + 64, 20), 1 FROM t1;
|
||||
|
||||
EXPLAIN SELECT b, SUM(c) FROM t1 GROUP BY b;
|
||||
EXPLAIN SELECT SQL_BIG_RESULT b, SUM(c) FROM t1 GROUP BY b;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo End of 5.0 tests
|
||||
|
|
|
@ -755,6 +755,97 @@ SELECT * FROM t1;
|
|||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# Bug#8283 - OPTIMIZE TABLE causes data loss
|
||||
#
|
||||
SET @@myisam_repair_threads=2;
|
||||
SHOW VARIABLES LIKE 'myisam_repair%';
|
||||
#
|
||||
# Test OPTIMIZE. This creates a new data file.
|
||||
CREATE TABLE t1 (
|
||||
`_id` int(11) NOT NULL default '0',
|
||||
`url` text,
|
||||
`email` text,
|
||||
`description` text,
|
||||
`loverlap` int(11) default NULL,
|
||||
`roverlap` int(11) default NULL,
|
||||
`lneighbor_id` int(11) default NULL,
|
||||
`rneighbor_id` int(11) default NULL,
|
||||
`length_` int(11) default NULL,
|
||||
`sequence` mediumtext,
|
||||
`name` text,
|
||||
`_obj_class` text NOT NULL,
|
||||
PRIMARY KEY (`_id`),
|
||||
UNIQUE KEY `sequence_name_index` (`name`(50)),
|
||||
KEY (`length_`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
||||
#
|
||||
INSERT INTO t1 VALUES
|
||||
(1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample1',''),
|
||||
(2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample2',''),
|
||||
(3,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample3',''),
|
||||
(4,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample4',''),
|
||||
(5,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample5',''),
|
||||
(6,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample6',''),
|
||||
(7,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample7',''),
|
||||
(8,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample8',''),
|
||||
(9,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample9','');
|
||||
#
|
||||
SELECT _id FROM t1;
|
||||
DELETE FROM t1 WHERE _id < 8;
|
||||
--replace_column 6 # 7 # 8 # 9 # 11 # 12 # 13 # 14 # 15 # 16 #
|
||||
SHOW TABLE STATUS LIKE 't1';
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
OPTIMIZE TABLE t1;
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
--replace_column 6 # 7 # 8 # 9 # 11 # 12 # 13 # 14 # 15 # 16 #
|
||||
SHOW TABLE STATUS LIKE 't1';
|
||||
SELECT _id FROM t1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Test REPAIR QUICK. This retains the old data file.
|
||||
CREATE TABLE t1 (
|
||||
`_id` int(11) NOT NULL default '0',
|
||||
`url` text,
|
||||
`email` text,
|
||||
`description` text,
|
||||
`loverlap` int(11) default NULL,
|
||||
`roverlap` int(11) default NULL,
|
||||
`lneighbor_id` int(11) default NULL,
|
||||
`rneighbor_id` int(11) default NULL,
|
||||
`length_` int(11) default NULL,
|
||||
`sequence` mediumtext,
|
||||
`name` text,
|
||||
`_obj_class` text NOT NULL,
|
||||
PRIMARY KEY (`_id`),
|
||||
UNIQUE KEY `sequence_name_index` (`name`(50)),
|
||||
KEY (`length_`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
||||
#
|
||||
INSERT INTO t1 VALUES
|
||||
(1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample1',''),
|
||||
(2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample2',''),
|
||||
(3,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample3',''),
|
||||
(4,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample4',''),
|
||||
(5,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample5',''),
|
||||
(6,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample6',''),
|
||||
(7,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample7',''),
|
||||
(8,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample8',''),
|
||||
(9,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample9','');
|
||||
#
|
||||
SELECT _id FROM t1;
|
||||
DELETE FROM t1 WHERE _id < 8;
|
||||
--replace_column 6 # 7 # 8 # 9 # 11 # 12 # 13 # 14 # 15 # 16 #
|
||||
SHOW TABLE STATUS LIKE 't1';
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
REPAIR TABLE t1 QUICK;
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
--replace_column 6 # 7 # 8 # 9 # 11 # 12 # 13 # 14 # 15 # 16 #
|
||||
SHOW TABLE STATUS LIKE 't1';
|
||||
SELECT _id FROM t1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
SET @@myisam_repair_threads=1;
|
||||
SHOW VARIABLES LIKE 'myisam_repair%';
|
||||
# Test varchar
|
||||
#
|
||||
|
||||
|
|
|
@ -283,6 +283,15 @@ select a, max(b) from t1 group by a with rollup;
|
|||
select distinct a, max(b) from t1 group by a with rollup;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Bug #20825: rollup puts non-equal values together
|
||||
#
|
||||
create table t1 (a varchar(22) not null , b int);
|
||||
insert into t1 values ("2006-07-01 21:30", 1), ("2006-07-01 23:30", 10);
|
||||
select left(a,10), a, sum(b) from t1 group by 1,2 with rollup;
|
||||
select left(a,10) x, a, sum(b) from t1 group by x,a with rollup;
|
||||
drop table t1;
|
||||
|
||||
# End of 4.1 tests
|
||||
|
||||
#
|
||||
|
@ -318,4 +327,3 @@ SELECT * FROM v1;
|
|||
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1;
|
||||
# End of 4.1 tests
|
||||
|
|
|
@ -72,4 +72,17 @@ disconnect con2;
|
|||
disconnect con1;
|
||||
connection default;
|
||||
|
||||
#
|
||||
# Bug#14959: ALTER TABLE isn't able to rename a view
|
||||
#
|
||||
create table t1(f1 int);
|
||||
create view v1 as select * from t1;
|
||||
alter table v1 rename to v2;
|
||||
--error 1146
|
||||
alter table v1 rename to v2;
|
||||
rename table v2 to v1;
|
||||
--error 1050
|
||||
rename table v2 to v1;
|
||||
drop view v1;
|
||||
drop table t1;
|
||||
# End of 4.1 tests
|
||||
|
|
|
@ -45,4 +45,42 @@ SHOW INDEX FROM t1;
|
|||
SET myisam_repair_threads=@@global.myisam_repair_threads;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# BUG#22562 - REPAIR TABLE .. USE_FRM causes server crash on Windows and
|
||||
# server hangs on Linux
|
||||
#
|
||||
CREATE TABLE t1(a INT);
|
||||
USE mysql;
|
||||
REPAIR TABLE test.t1 USE_FRM;
|
||||
USE test;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# BUG#23175 - MYISAM crash/repair failed during repair
|
||||
#
|
||||
CREATE TABLE t1(a CHAR(255), KEY(a));
|
||||
SET myisam_sort_buffer_size=4096;
|
||||
INSERT INTO t1 VALUES
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),('0'),
|
||||
('0'),('0'),('0'),('0'),('0'),('0'),('0');
|
||||
SET myisam_repair_threads=2;
|
||||
REPAIR TABLE t1;
|
||||
SET myisam_repair_threads=@@global.myisam_repair_threads;
|
||||
SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size;
|
||||
DROP TABLE t1;
|
||||
|
||||
# End of 4.1 tests
|
||||
|
|
|
@ -2996,5 +2996,99 @@ SELECT * FROM t1 LEFT JOIN t2 ON t2.b=t1.a INNER JOIN t3 ON t3.d=t1.id
|
|||
SELECT * FROM t1 LEFT JOIN t2 ON t2.b=t1.a INNER JOIN t3 ON t3.d=t1.id
|
||||
WHERE t1.id=2;
|
||||
|
||||
DROP TABLE t1,t2,t3;
|
||||
|
||||
#
|
||||
# Bug#20503: Server crash due to the ORDER clause isn't taken into account
|
||||
# while space allocation
|
||||
#
|
||||
create table t1 (c1 varchar(1), c2 int, c3 int, c4 int, c5 int, c6 int,
|
||||
c7 int, c8 int, c9 int, fulltext key (`c1`));
|
||||
select distinct match (`c1`) against ('z') , c2, c3, c4,c5, c6,c7, c8
|
||||
from t1 where c9=1 order by c2, c2;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Bug #22735: no equality propagation for BETWEEN and IN with STRING arguments
|
||||
#
|
||||
|
||||
CREATE TABLE t1 (pk varchar(10) PRIMARY KEY, fk varchar(16));
|
||||
CREATE TABLE t2 (pk varchar(16) PRIMARY KEY, fk varchar(10));
|
||||
|
||||
INSERT INTO t1 VALUES
|
||||
('d','dddd'), ('i','iii'), ('a','aa'), ('b','bb'), ('g','gg'),
|
||||
('e','eee'), ('c','cccc'), ('h','hhh'), ('j','jjj'), ('f','fff');
|
||||
INSERT INTO t2 VALUES
|
||||
('jjj', 'j'), ('cc','c'), ('ccc','c'), ('aaa', 'a'), ('jjjj','j'),
|
||||
('hhh','h'), ('gg','g'), ('fff','f'), ('ee','e'), ('ffff','f'),
|
||||
('bbb','b'), ('ff','f'), ('cccc','c'), ('dddd','d'), ('jj','j'),
|
||||
('aaaa','a'), ('bb','b'), ('eeee','e'), ('aa','a'), ('hh','h');
|
||||
|
||||
EXPLAIN SELECT t2.*
|
||||
FROM t1 JOIN t2 ON t2.fk=t1.pk
|
||||
WHERE t2.fk < 'c' AND t2.pk=t1.fk;
|
||||
EXPLAIN SELECT t2.*
|
||||
FROM t1 JOIN t2 ON t2.fk=t1.pk
|
||||
WHERE t2.fk BETWEEN 'a' AND 'b' AND t2.pk=t1.fk;
|
||||
EXPLAIN SELECT t2.*
|
||||
FROM t1 JOIN t2 ON t2.fk=t1.pk
|
||||
WHERE t2.fk IN ('a','b') AND t2.pk=t1.fk;
|
||||
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
#
|
||||
# Bug #22367: Optimizer uses ref join type instead of eq_ref for simple
|
||||
# join on strings
|
||||
#
|
||||
CREATE TABLE t1 (a int, b varchar(20) NOT NULL, PRIMARY KEY(a));
|
||||
CREATE TABLE t2 (a int, b varchar(20) NOT NULL,
|
||||
PRIMARY KEY (a), UNIQUE KEY (b));
|
||||
INSERT INTO t1 VALUES (1,'a'),(2,'b'),(3,'c');
|
||||
INSERT INTO t2 VALUES (1,'a'),(2,'b'),(3,'c');
|
||||
|
||||
EXPLAIN SELECT t1.a FROM t1 LEFT JOIN t2 ON t2.b=t1.b WHERE t1.a=3;
|
||||
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
#
|
||||
# Bug #19579: predicates that become sargable after reading const tables
|
||||
# are not taken into account by optimizer
|
||||
#
|
||||
|
||||
CREATE TABLE t1(id int PRIMARY KEY, b int, e int);
|
||||
CREATE TABLE t2(i int, a int, INDEX si(i), INDEX ai(a));
|
||||
CREATE TABLE t3(a int PRIMARY KEY, c char(4), INDEX ci(c));
|
||||
|
||||
INSERT INTO t1 VALUES
|
||||
(1,10,19), (2,20,22), (4,41,42), (9,93,95), (7, 77,79),
|
||||
(6,63,67), (5,55,58), (3,38,39), (8,81,89);
|
||||
INSERT INTO t2 VALUES
|
||||
(21,210), (41,410), (82,820), (83,830), (84,840),
|
||||
(65,650), (51,510), (37,370), (94,940), (76,760),
|
||||
(22,220), (33,330), (40,400), (95,950), (38,380),
|
||||
(67,670), (88,880), (57,570), (96,960), (97,970);
|
||||
INSERT INTO t3 VALUES
|
||||
(210,'bb'), (950,'ii'), (400,'ab'), (500,'ee'), (220,'gg'),
|
||||
(440,'gg'), (310,'eg'), (380,'ee'), (840,'bb'), (830,'ff'),
|
||||
(230,'aa'), (960,'ii'), (410,'aa'), (510,'ee'), (290,'bb'),
|
||||
(450,'gg'), (320,'dd'), (390,'hh'), (850,'jj'), (860,'ff');
|
||||
|
||||
EXPLAIN
|
||||
SELECT t3.a FROM t1,t2 FORCE INDEX (si),t3
|
||||
WHERE t1.id = 8 AND t2.i BETWEEN t1.b AND t1.e AND
|
||||
t3.a=t2.a AND t3.c IN ('bb','ee');
|
||||
EXPLAIN
|
||||
SELECT t3.a FROM t1,t2,t3
|
||||
WHERE t1.id = 8 AND t2.i BETWEEN t1.b AND t1.e AND
|
||||
t3.a=t2.a AND t3.c IN ('bb','ee') ;
|
||||
|
||||
EXPLAIN
|
||||
SELECT t3.a FROM t1,t2 FORCE INDEX (si),t3
|
||||
WHERE t1.id = 8 AND (t2.i=t1.b OR t2.i=t1.e) AND t3.a=t2.a AND
|
||||
t3.c IN ('bb','ee');
|
||||
EXPLAIN
|
||||
SELECT t3.a FROM t1,t2,t3
|
||||
WHERE t1.id = 8 AND (t2.i=t1.b OR t2.i=t1.e) AND t3.a=t2.a AND
|
||||
t3.c IN ('bb','ee');
|
||||
|
||||
DROP TABLE t1,t2,t3;
|
||||
|
|
|
@ -2370,6 +2370,32 @@ explain select * from t1 where not exists
|
|||
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# Bug#21798: memory leak during query execution with subquery in column
|
||||
# list using a function
|
||||
#
|
||||
CREATE TABLE t1 (a VARCHAR(250), b INT auto_increment, PRIMARY KEY (b));
|
||||
insert into t1 (a) values (FLOOR(rand() * 100));
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
insert into t1 (a) select FLOOR(rand() * 100) from t1;
|
||||
|
||||
SELECT a,
|
||||
(SELECT REPEAT(' ',250) FROM t1 i1
|
||||
WHERE i1.b=t1.a ORDER BY RAND() LIMIT 1) AS a
|
||||
FROM t1 ORDER BY a LIMIT 5;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# Bug #21540: Subqueries with no from and aggregate functions return
|
||||
# wrong results
|
||||
|
|
|
@ -385,3 +385,12 @@ insert into t1 values (40);
|
|||
flush tables;
|
||||
select f1 from t1 where f1 in (select f1 from t1);
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Bug#22183: Unhandled NULL caused server crash
|
||||
#
|
||||
create table t1 as
|
||||
select from_days(s) as date,t
|
||||
from (select 1 as s,'t' as t union select null, null ) as sub1;
|
||||
select group_concat(t) from t1 group by week(date)/10;
|
||||
drop table t1;
|
||||
|
|
|
@ -127,4 +127,13 @@ create table t1 (a set('x','y') default 'x');
|
|||
alter table t1 alter a set default 'z';
|
||||
drop table t1;
|
||||
|
||||
|
||||
#
|
||||
# Bug#20922 mysql removes a name of first column in a table
|
||||
#
|
||||
create table t1 (f1 int);
|
||||
alter table t1 add f2 enum(0xFFFF);
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
# End of 4.1 tests
|
||||
|
|
|
@ -2879,4 +2879,19 @@ SHOW CREATE VIEW v1;
|
|||
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
#
|
||||
# Bug #16813 (WITH CHECK OPTION doesn't work with UPDATE)
|
||||
#
|
||||
CREATE TABLE t1(id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, val INT UNSIGNED NOT NULL);
|
||||
CREATE VIEW v1 AS SELECT id, val FROM t1 WHERE val >= 1 AND val <= 5 WITH CHECK OPTION;
|
||||
INSERT INTO v1 (val) VALUES (2);
|
||||
INSERT INTO v1 (val) VALUES (4);
|
||||
-- error 1369
|
||||
INSERT INTO v1 (val) VALUES (6);
|
||||
-- error 1369
|
||||
UPDATE v1 SET val=6 WHERE id=2;
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo End of 5.0 tests.
|
||||
|
|
|
@ -70,7 +70,6 @@ static void my_aiowait(my_aio_result *result);
|
|||
#define IO_ROUND_UP(X) (((X)+IO_SIZE-1) & ~(IO_SIZE-1))
|
||||
#define IO_ROUND_DN(X) ( (X) & ~(IO_SIZE-1))
|
||||
|
||||
|
||||
/*
|
||||
Setup internal pointers inside IO_CACHE
|
||||
|
||||
|
@ -506,65 +505,366 @@ int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)
|
|||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
#ifdef THREAD
|
||||
/* Prepare IO_CACHE for shared use */
|
||||
void init_io_cache_share(IO_CACHE *info, IO_CACHE_SHARE *s, uint num_threads)
|
||||
/*
|
||||
Prepare IO_CACHE for shared use.
|
||||
|
||||
SYNOPSIS
|
||||
init_io_cache_share()
|
||||
read_cache A read cache. This will be copied for
|
||||
every thread after setup.
|
||||
cshare The share.
|
||||
write_cache If non-NULL a write cache that is to be
|
||||
synchronized with the read caches.
|
||||
num_threads Number of threads sharing the cache
|
||||
including the write thread if any.
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
The shared cache is used so: One IO_CACHE is initialized with
|
||||
init_io_cache(). This includes the allocation of a buffer. Then a
|
||||
share is allocated and init_io_cache_share() is called with the io
|
||||
cache and the share. Then the io cache is copied for each thread. So
|
||||
every thread has its own copy of IO_CACHE. But the allocated buffer
|
||||
is shared because cache->buffer is the same for all caches.
|
||||
|
||||
One thread reads data from the file into the buffer. All threads
|
||||
read from the buffer, but every thread maintains its own set of
|
||||
pointers into the buffer. When all threads have used up the buffer
|
||||
contents, one of the threads reads the next block of data into the
|
||||
buffer. To accomplish this, each thread enters the cache lock before
|
||||
accessing the buffer. They wait in lock_io_cache() until all threads
|
||||
joined the lock. The last thread entering the lock is in charge of
|
||||
reading from file to buffer. It wakes all threads when done.
|
||||
|
||||
Synchronizing a write cache to the read caches works so: Whenever
|
||||
the write buffer needs a flush, the write thread enters the lock and
|
||||
waits for all other threads to enter the lock too. They do this when
|
||||
they have used up the read buffer. When all threads are in the lock,
|
||||
the write thread copies the write buffer to the read buffer and
|
||||
wakes all threads.
|
||||
|
||||
share->running_threads is the number of threads not being in the
|
||||
cache lock. When entering lock_io_cache() the number is decreased.
|
||||
When the thread that fills the buffer enters unlock_io_cache() the
|
||||
number is reset to the number of threads. The condition
|
||||
running_threads == 0 means that all threads are in the lock. Bumping
|
||||
up the number to the full count is non-intuitive. But increasing the
|
||||
number by one for each thread that leaves the lock could lead to a
|
||||
solo run of one thread. The last thread to join a lock reads from
|
||||
file to buffer, wakes the other threads, processes the data in the
|
||||
cache and enters the lock again. If no other thread left the lock
|
||||
meanwhile, it would think it's the last one again and read the next
|
||||
block...
|
||||
|
||||
The share has copies of 'error', 'buffer', 'read_end', and
|
||||
'pos_in_file' from the thread that filled the buffer. We may not be
|
||||
able to access this information directly from its cache because the
|
||||
thread may be removed from the share before the variables could be
|
||||
copied by all other threads. Or, if a write buffer is synchronized,
|
||||
it would change its 'pos_in_file' after waking the other threads,
|
||||
possibly before they could copy its value.
|
||||
|
||||
However, the 'buffer' variable in the share is for a synchronized
|
||||
write cache. It needs to know where to put the data. Otherwise it
|
||||
would need access to the read cache of one of the threads that is
|
||||
not yet removed from the share.
|
||||
|
||||
RETURN
|
||||
void
|
||||
*/
|
||||
|
||||
void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare,
|
||||
IO_CACHE *write_cache, uint num_threads)
|
||||
{
|
||||
DBUG_ASSERT(info->type == READ_CACHE);
|
||||
pthread_mutex_init(&s->mutex, MY_MUTEX_INIT_FAST);
|
||||
pthread_cond_init (&s->cond, 0);
|
||||
s->total=s->count=num_threads-1;
|
||||
s->active=0;
|
||||
info->share=s;
|
||||
info->read_function=_my_b_read_r;
|
||||
info->current_pos= info->current_end= 0;
|
||||
DBUG_ENTER("init_io_cache_share");
|
||||
DBUG_PRINT("io_cache_share", ("read_cache: 0x%lx share: 0x%lx "
|
||||
"write_cache: 0x%lx threads: %u",
|
||||
read_cache, cshare, write_cache, num_threads));
|
||||
|
||||
DBUG_ASSERT(num_threads > 1);
|
||||
DBUG_ASSERT(read_cache->type == READ_CACHE);
|
||||
DBUG_ASSERT(!write_cache || (write_cache->type == WRITE_CACHE));
|
||||
|
||||
pthread_mutex_init(&cshare->mutex, MY_MUTEX_INIT_FAST);
|
||||
pthread_cond_init(&cshare->cond, 0);
|
||||
pthread_cond_init(&cshare->cond_writer, 0);
|
||||
|
||||
cshare->running_threads= num_threads;
|
||||
cshare->total_threads= num_threads;
|
||||
cshare->error= 0; /* Initialize. */
|
||||
cshare->buffer= read_cache->buffer;
|
||||
cshare->read_end= NULL; /* See function comment of lock_io_cache(). */
|
||||
cshare->pos_in_file= 0; /* See function comment of lock_io_cache(). */
|
||||
cshare->source_cache= write_cache; /* Can be NULL. */
|
||||
|
||||
read_cache->share= cshare;
|
||||
read_cache->read_function= _my_b_read_r;
|
||||
read_cache->current_pos= NULL;
|
||||
read_cache->current_end= NULL;
|
||||
|
||||
if (write_cache)
|
||||
write_cache->share= cshare;
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Remove a thread from shared access to IO_CACHE
|
||||
Every thread should do that on exit for not
|
||||
to deadlock other threads
|
||||
Remove a thread from shared access to IO_CACHE.
|
||||
|
||||
SYNOPSIS
|
||||
remove_io_thread()
|
||||
cache The IO_CACHE to be removed from the share.
|
||||
|
||||
NOTE
|
||||
|
||||
Every thread must do that on exit for not to deadlock other threads.
|
||||
|
||||
The last thread destroys the pthread resources.
|
||||
|
||||
A writer flushes its cache first.
|
||||
|
||||
RETURN
|
||||
void
|
||||
*/
|
||||
void remove_io_thread(IO_CACHE *info)
|
||||
|
||||
void remove_io_thread(IO_CACHE *cache)
|
||||
{
|
||||
IO_CACHE_SHARE *s=info->share;
|
||||
IO_CACHE_SHARE *cshare= cache->share;
|
||||
uint total;
|
||||
DBUG_ENTER("remove_io_thread");
|
||||
|
||||
pthread_mutex_lock(&s->mutex);
|
||||
s->total--;
|
||||
if (! s->count--)
|
||||
pthread_cond_signal(&s->cond);
|
||||
pthread_mutex_unlock(&s->mutex);
|
||||
}
|
||||
/* If the writer goes, it needs to flush the write cache. */
|
||||
if (cache == cshare->source_cache)
|
||||
flush_io_cache(cache);
|
||||
|
||||
static int lock_io_cache(IO_CACHE *info, my_off_t pos)
|
||||
{
|
||||
int total;
|
||||
IO_CACHE_SHARE *s=info->share;
|
||||
pthread_mutex_lock(&cshare->mutex);
|
||||
DBUG_PRINT("io_cache_share", ("%s: 0x%lx",
|
||||
(cache == cshare->source_cache) ?
|
||||
"writer" : "reader", cache));
|
||||
|
||||
pthread_mutex_lock(&s->mutex);
|
||||
if (!s->count)
|
||||
/* Remove from share. */
|
||||
total= --cshare->total_threads;
|
||||
DBUG_PRINT("io_cache_share", ("remaining threads: %u", total));
|
||||
|
||||
/* Detach from share. */
|
||||
cache->share= NULL;
|
||||
|
||||
/* If the writer goes, let the readers know. */
|
||||
if (cache == cshare->source_cache)
|
||||
{
|
||||
s->count=s->total;
|
||||
return 1;
|
||||
DBUG_PRINT("io_cache_share", ("writer leaves"));
|
||||
cshare->source_cache= NULL;
|
||||
}
|
||||
|
||||
total=s->total;
|
||||
s->count--;
|
||||
while (!s->active || s->active->pos_in_file < pos)
|
||||
pthread_cond_wait(&s->cond, &s->mutex);
|
||||
/* If all threads are waiting for me to join the lock, wake them. */
|
||||
if (!--cshare->running_threads)
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("the last running thread leaves, wake all"));
|
||||
pthread_cond_signal(&cshare->cond_writer);
|
||||
pthread_cond_broadcast(&cshare->cond);
|
||||
}
|
||||
|
||||
if (s->total < total &&
|
||||
(!s->active || s->active->pos_in_file < pos))
|
||||
return 1;
|
||||
pthread_mutex_unlock(&cshare->mutex);
|
||||
|
||||
pthread_mutex_unlock(&s->mutex);
|
||||
return 0;
|
||||
if (!total)
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("last thread removed, destroy share"));
|
||||
pthread_cond_destroy (&cshare->cond_writer);
|
||||
pthread_cond_destroy (&cshare->cond);
|
||||
pthread_mutex_destroy(&cshare->mutex);
|
||||
}
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
static void unlock_io_cache(IO_CACHE *info)
|
||||
|
||||
/*
|
||||
Lock IO cache and wait for all other threads to join.
|
||||
|
||||
SYNOPSIS
|
||||
lock_io_cache()
|
||||
cache The cache of the thread entering the lock.
|
||||
pos File position of the block to read.
|
||||
Unused for the write thread.
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Wait for all threads to finish with the current buffer. We want
|
||||
all threads to proceed in concert. The last thread to join
|
||||
lock_io_cache() will read the block from file and all threads start
|
||||
to use it. Then they will join again for reading the next block.
|
||||
|
||||
The waiting threads detect a fresh buffer by comparing
|
||||
cshare->pos_in_file with the position they want to process next.
|
||||
Since the first block may start at position 0, we take
|
||||
cshare->read_end as an additional condition. This variable is
|
||||
initialized to NULL and will be set after a block of data is written
|
||||
to the buffer.
|
||||
|
||||
RETURN
|
||||
1 OK, lock in place, go ahead and read.
|
||||
0 OK, unlocked, another thread did the read.
|
||||
*/
|
||||
|
||||
static int lock_io_cache(IO_CACHE *cache, my_off_t pos)
|
||||
{
|
||||
pthread_cond_broadcast(&info->share->cond);
|
||||
pthread_mutex_unlock(&info->share->mutex);
|
||||
IO_CACHE_SHARE *cshare= cache->share;
|
||||
DBUG_ENTER("lock_io_cache");
|
||||
|
||||
/* Enter the lock. */
|
||||
pthread_mutex_lock(&cshare->mutex);
|
||||
cshare->running_threads--;
|
||||
DBUG_PRINT("io_cache_share", ("%s: 0x%lx pos: %lu running: %u",
|
||||
(cache == cshare->source_cache) ?
|
||||
"writer" : "reader", cache, (ulong) pos,
|
||||
cshare->running_threads));
|
||||
|
||||
if (cshare->source_cache)
|
||||
{
|
||||
/* A write cache is synchronized to the read caches. */
|
||||
|
||||
if (cache == cshare->source_cache)
|
||||
{
|
||||
/* The writer waits until all readers are here. */
|
||||
while (cshare->running_threads)
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("writer waits in lock"));
|
||||
pthread_cond_wait(&cshare->cond_writer, &cshare->mutex);
|
||||
}
|
||||
DBUG_PRINT("io_cache_share", ("writer awoke, going to copy"));
|
||||
|
||||
/* Stay locked. Leave the lock later by unlock_io_cache(). */
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/* The last thread wakes the writer. */
|
||||
if (!cshare->running_threads)
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("waking writer"));
|
||||
pthread_cond_signal(&cshare->cond_writer);
|
||||
}
|
||||
|
||||
/*
|
||||
Readers wait until the data is copied from the writer. Another
|
||||
reason to stop waiting is the removal of the write thread. If this
|
||||
happens, we leave the lock with old data in the buffer.
|
||||
*/
|
||||
while ((!cshare->read_end || (cshare->pos_in_file < pos)) &&
|
||||
cshare->source_cache)
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("reader waits in lock"));
|
||||
pthread_cond_wait(&cshare->cond, &cshare->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
If the writer was removed from the share while this thread was
|
||||
asleep, we need to simulate an EOF condition. The writer cannot
|
||||
reset the share variables as they might still be in use by readers
|
||||
of the last block. When we awake here then because the last
|
||||
joining thread signalled us. If the writer is not the last, it
|
||||
will not signal. So it is safe to clear the buffer here.
|
||||
*/
|
||||
if (!cshare->read_end || (cshare->pos_in_file < pos))
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("reader found writer removed. EOF"));
|
||||
cshare->read_end= cshare->buffer; /* Empty buffer. */
|
||||
cshare->error= 0; /* EOF is not an error. */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
There are read caches only. The last thread arriving in
|
||||
lock_io_cache() continues with a locked cache and reads the block.
|
||||
*/
|
||||
if (!cshare->running_threads)
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("last thread joined, going to read"));
|
||||
/* Stay locked. Leave the lock later by unlock_io_cache(). */
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/*
|
||||
All other threads wait until the requested block is read by the
|
||||
last thread arriving. Another reason to stop waiting is the
|
||||
removal of a thread. If this leads to all threads being in the
|
||||
lock, we have to continue also. The first of the awaken threads
|
||||
will then do the read.
|
||||
*/
|
||||
while ((!cshare->read_end || (cshare->pos_in_file < pos)) &&
|
||||
cshare->running_threads)
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("reader waits in lock"));
|
||||
pthread_cond_wait(&cshare->cond, &cshare->mutex);
|
||||
}
|
||||
|
||||
/* If the block is not yet read, continue with a locked cache and read. */
|
||||
if (!cshare->read_end || (cshare->pos_in_file < pos))
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("reader awoke, going to read"));
|
||||
/* Stay locked. Leave the lock later by unlock_io_cache(). */
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/* Another thread did read the block already. */
|
||||
}
|
||||
DBUG_PRINT("io_cache_share", ("reader awoke, going to process %u bytes",
|
||||
cshare->read_end ? (uint)
|
||||
(cshare->read_end - cshare->buffer) : 0));
|
||||
|
||||
/*
|
||||
Leave the lock. Do not call unlock_io_cache() later. The thread that
|
||||
filled the buffer did this and marked all threads as running.
|
||||
*/
|
||||
pthread_mutex_unlock(&cshare->mutex);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Unlock IO cache.
|
||||
|
||||
SYNOPSIS
|
||||
unlock_io_cache()
|
||||
cache The cache of the thread leaving the lock.
|
||||
|
||||
NOTE
|
||||
This is called by the thread that filled the buffer. It marks all
|
||||
threads as running and awakes them. This must not be done by any
|
||||
other thread.
|
||||
|
||||
Do not signal cond_writer. Either there is no writer or the writer
|
||||
is the only one who can call this function.
|
||||
|
||||
The reason for resetting running_threads to total_threads before
|
||||
waking all other threads is that it could be possible that this
|
||||
thread is so fast with processing the buffer that it enters the lock
|
||||
before even one other thread has left it. If every awoken thread
|
||||
would increase running_threads by one, this thread could think that
|
||||
he is again the last to join and would not wait for the other
|
||||
threads to process the data.
|
||||
|
||||
RETURN
|
||||
void
|
||||
*/
|
||||
|
||||
static void unlock_io_cache(IO_CACHE *cache)
|
||||
{
|
||||
IO_CACHE_SHARE *cshare= cache->share;
|
||||
DBUG_ENTER("unlock_io_cache");
|
||||
DBUG_PRINT("io_cache_share", ("%s: 0x%lx pos: %lu running: %u",
|
||||
(cache == cshare->source_cache) ?
|
||||
"writer" : "reader",
|
||||
cache, (ulong) cshare->pos_in_file,
|
||||
cshare->total_threads));
|
||||
|
||||
cshare->running_threads= cshare->total_threads;
|
||||
pthread_cond_broadcast(&cshare->cond);
|
||||
pthread_mutex_unlock(&cshare->mutex);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
|
@ -573,7 +873,7 @@ static void unlock_io_cache(IO_CACHE *info)
|
|||
|
||||
SYNOPSIS
|
||||
_my_b_read_r()
|
||||
info IO_CACHE pointer
|
||||
cache IO_CACHE pointer
|
||||
Buffer Buffer to retrieve count bytes from file
|
||||
Count Number of bytes to read into Buffer
|
||||
|
||||
|
@ -585,7 +885,7 @@ static void unlock_io_cache(IO_CACHE *info)
|
|||
|
||||
It works as follows: when a thread tries to read from a file (that
|
||||
is, after using all the data from the (shared) buffer), it just
|
||||
hangs on lock_io_cache(), wating for other threads. When the very
|
||||
hangs on lock_io_cache(), waiting for other threads. When the very
|
||||
last thread attempts a read, lock_io_cache() returns 1, the thread
|
||||
does actual IO and unlock_io_cache(), which signals all the waiting
|
||||
threads that data is in the buffer.
|
||||
|
@ -605,16 +905,17 @@ static void unlock_io_cache(IO_CACHE *info)
|
|||
1 Error: can't read requested characters
|
||||
*/
|
||||
|
||||
int _my_b_read_r(register IO_CACHE *info, byte *Buffer, uint Count)
|
||||
int _my_b_read_r(register IO_CACHE *cache, byte *Buffer, uint Count)
|
||||
{
|
||||
my_off_t pos_in_file;
|
||||
uint length, diff_length, left_length;
|
||||
IO_CACHE_SHARE *cshare= cache->share;
|
||||
DBUG_ENTER("_my_b_read_r");
|
||||
|
||||
if ((left_length= (uint) (info->read_end - info->read_pos)))
|
||||
if ((left_length= (uint) (cache->read_end - cache->read_pos)))
|
||||
{
|
||||
DBUG_ASSERT(Count >= left_length); /* User is not using my_b_read() */
|
||||
memcpy(Buffer, info->read_pos, (size_t) (left_length));
|
||||
memcpy(Buffer, cache->read_pos, (size_t) (left_length));
|
||||
Buffer+= left_length;
|
||||
Count-= left_length;
|
||||
}
|
||||
|
@ -622,55 +923,133 @@ int _my_b_read_r(register IO_CACHE *info, byte *Buffer, uint Count)
|
|||
{
|
||||
int cnt, len;
|
||||
|
||||
pos_in_file= info->pos_in_file + (info->read_end - info->buffer);
|
||||
pos_in_file= cache->pos_in_file + (cache->read_end - cache->buffer);
|
||||
diff_length= (uint) (pos_in_file & (IO_SIZE-1));
|
||||
length=IO_ROUND_UP(Count+diff_length)-diff_length;
|
||||
length=(length <= info->read_length) ?
|
||||
length + IO_ROUND_DN(info->read_length - length) :
|
||||
length - IO_ROUND_UP(length - info->read_length) ;
|
||||
if (info->type != READ_FIFO &&
|
||||
(length > (info->end_of_file - pos_in_file)))
|
||||
length= (uint) (info->end_of_file - pos_in_file);
|
||||
length= ((length <= cache->read_length) ?
|
||||
length + IO_ROUND_DN(cache->read_length - length) :
|
||||
length - IO_ROUND_UP(length - cache->read_length));
|
||||
if (cache->type != READ_FIFO &&
|
||||
(length > (cache->end_of_file - pos_in_file)))
|
||||
length= (uint) (cache->end_of_file - pos_in_file);
|
||||
if (length == 0)
|
||||
{
|
||||
info->error= (int) left_length;
|
||||
cache->error= (int) left_length;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (lock_io_cache(info, pos_in_file))
|
||||
if (lock_io_cache(cache, pos_in_file))
|
||||
{
|
||||
info->share->active=info;
|
||||
if (info->seek_not_done) /* File touched, do seek */
|
||||
VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)));
|
||||
len=(int)my_read(info->file,info->buffer, length, info->myflags);
|
||||
info->read_end=info->buffer + (len == -1 ? 0 : len);
|
||||
info->error=(len == (int)length ? 0 : len);
|
||||
info->pos_in_file=pos_in_file;
|
||||
unlock_io_cache(info);
|
||||
/* With a synchronized write/read cache we won't come here... */
|
||||
DBUG_ASSERT(!cshare->source_cache);
|
||||
/*
|
||||
... unless the writer has gone before this thread entered the
|
||||
lock. Simulate EOF in this case. It can be distinguished by
|
||||
cache->file.
|
||||
*/
|
||||
if (cache->file < 0)
|
||||
len= 0;
|
||||
else
|
||||
{
|
||||
if (cache->seek_not_done) /* File touched, do seek */
|
||||
VOID(my_seek(cache->file, pos_in_file, MY_SEEK_SET, MYF(0)));
|
||||
len= (int) my_read(cache->file, cache->buffer, length, cache->myflags);
|
||||
}
|
||||
DBUG_PRINT("io_cache_share", ("read %d bytes", len));
|
||||
|
||||
cache->read_end= cache->buffer + (len == -1 ? 0 : len);
|
||||
cache->error= (len == (int)length ? 0 : len);
|
||||
cache->pos_in_file= pos_in_file;
|
||||
|
||||
/* Copy important values to the share. */
|
||||
cshare->error= cache->error;
|
||||
cshare->read_end= cache->read_end;
|
||||
cshare->pos_in_file= pos_in_file;
|
||||
|
||||
/* Mark all threads as running and wake them. */
|
||||
unlock_io_cache(cache);
|
||||
}
|
||||
else
|
||||
{
|
||||
info->error= info->share->active->error;
|
||||
info->read_end= info->share->active->read_end;
|
||||
info->pos_in_file= info->share->active->pos_in_file;
|
||||
len= (int) (info->error == -1 ? -1 : info->read_end-info->buffer);
|
||||
/*
|
||||
With a synchronized write/read cache readers always come here.
|
||||
Copy important values from the share.
|
||||
*/
|
||||
cache->error= cshare->error;
|
||||
cache->read_end= cshare->read_end;
|
||||
cache->pos_in_file= cshare->pos_in_file;
|
||||
|
||||
len= (int) ((cache->error == -1) ? -1 : cache->read_end - cache->buffer);
|
||||
}
|
||||
info->read_pos=info->buffer;
|
||||
info->seek_not_done=0;
|
||||
cache->read_pos= cache->buffer;
|
||||
cache->seek_not_done= 0;
|
||||
if (len <= 0)
|
||||
{
|
||||
info->error= (int) left_length;
|
||||
DBUG_PRINT("io_cache_share", ("reader error. len %d left %u",
|
||||
len, left_length));
|
||||
cache->error= (int) left_length;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
cnt= ((uint) len > Count) ? (int) Count : len;
|
||||
memcpy(Buffer, info->read_pos, (size_t) cnt);
|
||||
memcpy(Buffer, cache->read_pos, (size_t) cnt);
|
||||
Count -= cnt;
|
||||
Buffer+= cnt;
|
||||
left_length+= cnt;
|
||||
info->read_pos+= cnt;
|
||||
cache->read_pos+= cnt;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Copy data from write cache to read cache.
|
||||
|
||||
SYNOPSIS
|
||||
copy_to_read_buffer()
|
||||
write_cache The write cache.
|
||||
write_buffer The source of data, mostly the cache buffer.
|
||||
write_length The number of bytes to copy.
|
||||
|
||||
NOTE
|
||||
The write thread will wait for all read threads to join the cache
|
||||
lock. Then it copies the data over and wakes the read threads.
|
||||
|
||||
RETURN
|
||||
void
|
||||
*/
|
||||
|
||||
static void copy_to_read_buffer(IO_CACHE *write_cache,
|
||||
const byte *write_buffer, uint write_length)
|
||||
{
|
||||
IO_CACHE_SHARE *cshare= write_cache->share;
|
||||
|
||||
DBUG_ASSERT(cshare->source_cache == write_cache);
|
||||
/*
|
||||
write_length is usually less or equal to buffer_length.
|
||||
It can be bigger if _my_b_write() is called with a big length.
|
||||
*/
|
||||
while (write_length)
|
||||
{
|
||||
uint copy_length= min(write_length, write_cache->buffer_length);
|
||||
int __attribute__((unused)) rc;
|
||||
|
||||
rc= lock_io_cache(write_cache, write_cache->pos_in_file);
|
||||
/* The writing thread does always have the lock when it awakes. */
|
||||
DBUG_ASSERT(rc);
|
||||
|
||||
memcpy(cshare->buffer, write_buffer, copy_length);
|
||||
|
||||
cshare->error= 0;
|
||||
cshare->read_end= cshare->buffer + copy_length;
|
||||
cshare->pos_in_file= write_cache->pos_in_file;
|
||||
|
||||
/* Mark all threads as running and wake them. */
|
||||
unlock_io_cache(write_cache);
|
||||
|
||||
write_buffer+= copy_length;
|
||||
write_length-= copy_length;
|
||||
}
|
||||
}
|
||||
#endif /*THREAD*/
|
||||
|
||||
|
||||
/*
|
||||
|
@ -1022,6 +1401,7 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
|
|||
Buffer+=rest_length;
|
||||
Count-=rest_length;
|
||||
info->write_pos+=rest_length;
|
||||
|
||||
if (my_b_flush_io_cache(info,1))
|
||||
return 1;
|
||||
if (Count >= IO_SIZE)
|
||||
|
@ -1034,6 +1414,23 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
|
|||
}
|
||||
if (my_write(info->file,Buffer,(uint) length,info->myflags | MY_NABP))
|
||||
return info->error= -1;
|
||||
|
||||
#ifdef THREAD
|
||||
/*
|
||||
In case of a shared I/O cache with a writer we normally do direct
|
||||
write cache to read cache copy. Simulate this here by direct
|
||||
caller buffer to read cache copy. Do it after the write so that
|
||||
the cache readers actions on the flushed part can go in parallel
|
||||
with the write of the extra stuff. copy_to_read_buffer()
|
||||
synchronizes writer and readers so that after this call the
|
||||
readers can act on the extra stuff while the writer can go ahead
|
||||
and prepare the next output. copy_to_read_buffer() relies on
|
||||
info->pos_in_file.
|
||||
*/
|
||||
if (info->share)
|
||||
copy_to_read_buffer(info, Buffer, length);
|
||||
#endif
|
||||
|
||||
Count-=length;
|
||||
Buffer+=length;
|
||||
info->pos_in_file+=length;
|
||||
|
@ -1054,6 +1451,14 @@ int my_b_append(register IO_CACHE *info, const byte *Buffer, uint Count)
|
|||
{
|
||||
uint rest_length,length;
|
||||
|
||||
#ifdef THREAD
|
||||
/*
|
||||
Assert that we cannot come here with a shared cache. If we do one
|
||||
day, we might need to add a call to copy_to_read_buffer().
|
||||
*/
|
||||
DBUG_ASSERT(!info->share);
|
||||
#endif
|
||||
|
||||
lock_append_buffer(info);
|
||||
rest_length=(uint) (info->write_end - info->write_pos);
|
||||
if (Count <= rest_length)
|
||||
|
@ -1114,6 +1519,14 @@ int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count,
|
|||
uint length;
|
||||
int error=0;
|
||||
|
||||
#ifdef THREAD
|
||||
/*
|
||||
Assert that we cannot come here with a shared cache. If we do one
|
||||
day, we might need to add a call to copy_to_read_buffer().
|
||||
*/
|
||||
DBUG_ASSERT(!info->share);
|
||||
#endif
|
||||
|
||||
if (pos < info->pos_in_file)
|
||||
{
|
||||
/* Of no overlap, write everything without buffering */
|
||||
|
@ -1190,6 +1603,17 @@ int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock)
|
|||
|
||||
if ((length=(uint) (info->write_pos - info->write_buffer)))
|
||||
{
|
||||
#ifdef THREAD
|
||||
/*
|
||||
In case of a shared I/O cache with a writer we do direct write
|
||||
cache to read cache copy. Do it before the write here so that
|
||||
the readers can work in parallel with the write.
|
||||
copy_to_read_buffer() relies on info->pos_in_file.
|
||||
*/
|
||||
if (info->share)
|
||||
copy_to_read_buffer(info, info->write_buffer, length);
|
||||
#endif
|
||||
|
||||
pos_in_file=info->pos_in_file;
|
||||
/*
|
||||
If we have append cache, we always open the file with
|
||||
|
@ -1269,16 +1693,10 @@ int end_io_cache(IO_CACHE *info)
|
|||
|
||||
#ifdef THREAD
|
||||
/*
|
||||
if IO_CACHE is shared between several threads, only one
|
||||
thread needs to call end_io_cache() - just as init_io_cache()
|
||||
should be called only once and then memcopy'ed
|
||||
Every thread must call remove_io_thread(). The last one destroys
|
||||
the share elements.
|
||||
*/
|
||||
if (info->share)
|
||||
{
|
||||
pthread_cond_destroy(&info->share->cond);
|
||||
pthread_mutex_destroy(&info->share->mutex);
|
||||
info->share=0;
|
||||
}
|
||||
DBUG_ASSERT(!info->share || !info->share->total_threads);
|
||||
#endif
|
||||
|
||||
if ((pre_close=info->pre_close))
|
||||
|
|
|
@ -144,8 +144,6 @@ fi
|
|||
# Copy data directory, readme files etc
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
cp COPYING EXCEPTIONS-CLIENT $DESTDIR/
|
||||
|
||||
# FIXME is there ever a data directory to copy?
|
||||
if [ -d win/data ] ; then
|
||||
cp -pR win/data $DESTDIR/data
|
||||
|
@ -159,9 +157,13 @@ mkdir $DESTDIR/Docs
|
|||
cp Docs/INSTALL-BINARY $DESTDIR/Docs/
|
||||
cp Docs/manual.chm $DESTDIR/Docs/ || /bin/true
|
||||
cp ChangeLog $DESTDIR/Docs/ || /bin/true
|
||||
cp COPYING $DESTDIR/Docs/
|
||||
cp support-files/my-*.ini $DESTDIR/
|
||||
|
||||
if [ -f COPYING ] ; then
|
||||
cp COPYING EXCEPTIONS-CLIENT $DESTDIR/
|
||||
cp COPYING $DESTDIR/Docs/
|
||||
fi
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# These will be filled in when we enable embedded. Note that if no
|
||||
# argument is given, it is copied if exists, else a check is done.
|
||||
|
@ -170,7 +172,8 @@ cp support-files/my-*.ini $DESTDIR/
|
|||
copy_embedded()
|
||||
{
|
||||
mkdir -p $DESTDIR/Embedded/DLL/release \
|
||||
$DESTDIR/Embedded/static/release
|
||||
$DESTDIR/Embedded/static/release \
|
||||
$DESTDIR/include
|
||||
cp libmysqld/libmysqld.def $DESTDIR/include/
|
||||
cp libmysqld/$TARGET/mysqlserver.lib $DESTDIR/Embedded/static/release/
|
||||
cp libmysqld/$TARGET/libmysqld.dll $DESTDIR/Embedded/DLL/release/
|
||||
|
@ -211,6 +214,9 @@ fi
|
|||
mkdir -p $DESTDIR/examples/tests
|
||||
cp tests/*.res tests/*.tst tests/*.pl tests/*.c $DESTDIR/examples/tests/
|
||||
|
||||
mkdir -p $DESTDIR/examples/udf_example
|
||||
cp sql/udf_example.def sql/udf_example.vcproj sql/udf_example.c $DESTDIR/examples/udf_example/
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# FIXME why not copy it all in "include"?!
|
||||
# ----------------------------------------------------------------------
|
||||
|
@ -228,6 +234,7 @@ cp include/conf*.h \
|
|||
include/m_string.h \
|
||||
include/m_ctype.h \
|
||||
include/my_global.h \
|
||||
include/raid.h \
|
||||
include/typelib.h $DESTDIR/include/
|
||||
cp libmysql/libmysql.def $DESTDIR/include/
|
||||
|
||||
|
|
|
@ -132,11 +132,17 @@ bool Cached_item_decimal::cmp()
|
|||
{
|
||||
my_decimal tmp;
|
||||
my_decimal *ptmp= item->val_decimal(&tmp);
|
||||
if (null_value != item->null_value || my_decimal_cmp(&value, ptmp))
|
||||
if (null_value != item->null_value ||
|
||||
(!item->null_value && my_decimal_cmp(&value, ptmp)))
|
||||
{
|
||||
null_value= item->null_value;
|
||||
my_decimal2decimal(ptmp, &value);
|
||||
return TRUE;
|
||||
/* Save only not null values */
|
||||
if (!null_value)
|
||||
{
|
||||
my_decimal2decimal(ptmp, &value);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -1078,6 +1078,8 @@ bool Item_func_between::fix_fields(THD *thd, Item **ref)
|
|||
if (Item_func_opt_neg::fix_fields(thd, ref))
|
||||
return 1;
|
||||
|
||||
thd->lex->current_select->between_count++;
|
||||
|
||||
/* not_null_tables_cache == union(T1(e),T1(e1),T1(e2)) */
|
||||
if (pred_level && !negated)
|
||||
return 0;
|
||||
|
|
|
@ -446,6 +446,7 @@ public:
|
|||
negated= !negated;
|
||||
return this;
|
||||
}
|
||||
bool subst_argument_checker(byte **arg) { return TRUE; }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ MY_LOCALE *my_locale_by_name(const char *name);
|
|||
Feel free to raise this by the smallest amount you can to get the
|
||||
"execution_constants" test to pass.
|
||||
*/
|
||||
#define STACK_MIN_SIZE 9336 // Abort if less stack during eval.
|
||||
#define STACK_MIN_SIZE 10788 // Abort if less stack during eval.
|
||||
|
||||
#define STACK_MIN_SIZE_FOR_OPEN 1024*80
|
||||
#define STACK_BUFF_ALLOC 256 // For stack overrun checks
|
||||
|
@ -659,6 +659,9 @@ int quick_rm_table(enum db_type base,const char *db,
|
|||
const char *table_name);
|
||||
void close_cached_table(THD *thd, TABLE *table);
|
||||
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
|
||||
bool do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db,
|
||||
char *new_table_name, char *new_table_alias,
|
||||
bool skip_error);
|
||||
bool mysql_change_db(THD *thd,const char *name,bool no_access_check);
|
||||
void mysql_parse(THD *thd,char *inBuf,uint length);
|
||||
bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
|
||||
|
@ -722,7 +725,8 @@ bool mysql_xa_recover(THD *thd);
|
|||
|
||||
bool check_simple_select();
|
||||
|
||||
SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length);
|
||||
SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length,
|
||||
SORT_FIELD *sortorder);
|
||||
int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
||||
List<Item> &fields, List <Item> &all_fields, ORDER *order);
|
||||
int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
||||
|
|
|
@ -8376,6 +8376,7 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows,
|
|||
quick->quick_prefix_select= NULL;
|
||||
|
||||
quick->update_key_stat();
|
||||
quick->adjust_prefix_ranges();
|
||||
|
||||
DBUG_RETURN(quick);
|
||||
}
|
||||
|
@ -8605,6 +8606,42 @@ bool QUICK_GROUP_MIN_MAX_SELECT::add_range(SEL_ARG *sel_range)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Opens the ranges if there are more conditions in quick_prefix_select than
|
||||
the ones used for jumping through the prefixes.
|
||||
|
||||
SYNOPSIS
|
||||
QUICK_GROUP_MIN_MAX_SELECT::adjust_prefix_ranges()
|
||||
|
||||
NOTES
|
||||
quick_prefix_select is made over the conditions on the whole key.
|
||||
It defines a number of ranges of length x.
|
||||
However when jumping through the prefixes we use only the the first
|
||||
few most significant keyparts in the range key. However if there
|
||||
are more keyparts to follow the ones we are using we must make the
|
||||
condition on the key inclusive (because x < "ab" means
|
||||
x[0] < 'a' OR (x[0] == 'a' AND x[1] < 'b').
|
||||
To achive the above we must turn off the NEAR_MIN/NEAR_MAX
|
||||
*/
|
||||
void QUICK_GROUP_MIN_MAX_SELECT::adjust_prefix_ranges ()
|
||||
{
|
||||
if (quick_prefix_select &&
|
||||
group_prefix_len < quick_prefix_select->max_used_key_length)
|
||||
{
|
||||
DYNAMIC_ARRAY *arr;
|
||||
uint inx;
|
||||
|
||||
for (inx= 0, arr= &quick_prefix_select->ranges; inx < arr->elements; inx++)
|
||||
{
|
||||
QUICK_RANGE *range;
|
||||
|
||||
get_dynamic(arr, (gptr)&range, inx);
|
||||
range->flag &= ~(NEAR_MIN | NEAR_MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Determine the total number and length of the keys that will be used for
|
||||
index lookup.
|
||||
|
|
|
@ -295,6 +295,7 @@ protected:
|
|||
friend class QUICK_SELECT_DESC;
|
||||
friend class QUICK_INDEX_MERGE_SELECT;
|
||||
friend class QUICK_ROR_INTERSECT_SELECT;
|
||||
friend class QUICK_GROUP_MIN_MAX_SELECT;
|
||||
|
||||
DYNAMIC_ARRAY ranges; /* ordered array of range ptrs */
|
||||
QUICK_RANGE **cur_range; /* current element in ranges */
|
||||
|
@ -643,6 +644,7 @@ public:
|
|||
~QUICK_GROUP_MIN_MAX_SELECT();
|
||||
bool add_range(SEL_ARG *sel_range);
|
||||
void update_key_stat();
|
||||
void adjust_prefix_ranges();
|
||||
bool alloc_buffers();
|
||||
int init();
|
||||
int reset();
|
||||
|
|
|
@ -3450,13 +3450,20 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
|
|||
const char *field_name=0;
|
||||
const char *table_name=0;
|
||||
bool found_unaliased_non_uniq= 0;
|
||||
/*
|
||||
true if the item that we search for is a valid name reference
|
||||
(and not an item that happens to have a name).
|
||||
*/
|
||||
bool is_ref_by_name= 0;
|
||||
uint unaliased_counter;
|
||||
|
||||
LINT_INIT(unaliased_counter); // Dependent on found_unaliased
|
||||
|
||||
*unaliased= FALSE;
|
||||
|
||||
if (find->type() == Item::FIELD_ITEM || find->type() == Item::REF_ITEM)
|
||||
is_ref_by_name= (find->type() == Item::FIELD_ITEM ||
|
||||
find->type() == Item::REF_ITEM);
|
||||
if (is_ref_by_name)
|
||||
{
|
||||
field_name= ((Item_ident*) find)->field_name;
|
||||
table_name= ((Item_ident*) find)->table_name;
|
||||
|
@ -3568,7 +3575,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
|
|||
}
|
||||
}
|
||||
else if (!table_name && (find->eq(item,0) ||
|
||||
find->name && item->name &&
|
||||
is_ref_by_name && find->name && item->name &&
|
||||
!my_strcasecmp(system_charset_info,
|
||||
item->name,find->name)))
|
||||
{
|
||||
|
@ -4899,6 +4906,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
|
|||
|
||||
thd->set_query_id=1;
|
||||
select_lex->cond_count= 0;
|
||||
select_lex->between_count= 0;
|
||||
|
||||
for (table= tables; table; table= table->next_local)
|
||||
{
|
||||
|
|
|
@ -167,7 +167,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
|
|||
MYF(MY_FAE | MY_ZEROFILL));
|
||||
|
||||
if (!(sortorder= make_unireg_sortorder((ORDER*) order->first,
|
||||
&length)) ||
|
||||
&length, NULL)) ||
|
||||
(table->sort.found_records = filesort(thd, table, sortorder, length,
|
||||
select, HA_POS_ERROR,
|
||||
&examined_rows))
|
||||
|
|
|
@ -1138,7 +1138,7 @@ void st_select_lex::init_query()
|
|||
initialization is checked for failure.
|
||||
*/
|
||||
parent_lex->push_context(&context);
|
||||
cond_count= with_wild= 0;
|
||||
cond_count= between_count= with_wild= 0;
|
||||
conds_processed_with_permanent_arena= 0;
|
||||
ref_pointer_array= 0;
|
||||
select_n_having_items= 0;
|
||||
|
|
|
@ -530,7 +530,8 @@ public:
|
|||
list during split_sum_func
|
||||
*/
|
||||
uint select_n_having_items;
|
||||
uint cond_count; /* number of arguments of and/or/xor in where/having */
|
||||
uint cond_count; /* number of arguments of and/or/xor in where/having/on */
|
||||
uint between_count; /* number of between predicates in where/having/on */
|
||||
enum_parsing_place parsing_place; /* where we are parsing expression */
|
||||
bool with_sum_func; /* sum function indicator */
|
||||
/*
|
||||
|
|
|
@ -125,95 +125,147 @@ static TABLE_LIST *reverse_table_list(TABLE_LIST *table_list)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Rename a single table or a view
|
||||
|
||||
SYNPOSIS
|
||||
do_rename()
|
||||
thd Thread handle
|
||||
ren_table A table/view to be renamed
|
||||
new_db The database to which the table to be moved to
|
||||
new_table_name The new table/view name
|
||||
new_table_alias The new table/view alias
|
||||
skip_error Whether to skip error
|
||||
|
||||
DESCRIPTION
|
||||
Rename a single table or a view.
|
||||
|
||||
RETURN
|
||||
false Ok
|
||||
true rename failed
|
||||
*/
|
||||
|
||||
bool
|
||||
do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name,
|
||||
char *new_table_alias, bool skip_error)
|
||||
{
|
||||
int rc= 1;
|
||||
char name[FN_REFLEN];
|
||||
const char *new_alias, *old_alias;
|
||||
frm_type_enum frm_type;
|
||||
db_type table_type;
|
||||
|
||||
DBUG_ENTER("do_rename");
|
||||
|
||||
if (lower_case_table_names == 2)
|
||||
{
|
||||
old_alias= ren_table->alias;
|
||||
new_alias= new_table_alias;
|
||||
}
|
||||
else
|
||||
{
|
||||
old_alias= ren_table->table_name;
|
||||
new_alias= new_table_name;
|
||||
}
|
||||
sprintf(name,"%s/%s/%s%s",mysql_data_home,
|
||||
new_db, new_alias, reg_ext);
|
||||
unpack_filename(name, name);
|
||||
if (!access(name,F_OK))
|
||||
{
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
|
||||
DBUG_RETURN(1); // This can't be skipped
|
||||
}
|
||||
sprintf(name,"%s/%s/%s%s",mysql_data_home,
|
||||
ren_table->db, old_alias,
|
||||
reg_ext);
|
||||
unpack_filename(name, name);
|
||||
|
||||
frm_type= mysql_frm_type(thd, name, &table_type);
|
||||
switch (frm_type)
|
||||
{
|
||||
case FRMTYPE_TABLE:
|
||||
{
|
||||
if (table_type == DB_TYPE_UNKNOWN)
|
||||
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
|
||||
else
|
||||
{
|
||||
if (!(rc= mysql_rename_table(table_type, ren_table->db, old_alias,
|
||||
new_db, new_alias)))
|
||||
{
|
||||
if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db,
|
||||
old_alias,
|
||||
new_db,
|
||||
new_alias)))
|
||||
{
|
||||
/*
|
||||
We've succeeded in renaming table's .frm and in updating
|
||||
corresponding handler data, but have failed to update table's
|
||||
triggers appropriately. So let us revert operations on .frm
|
||||
and handler's data and report about failure to rename table.
|
||||
*/
|
||||
(void) mysql_rename_table(table_type, new_db, new_alias,
|
||||
ren_table->db, old_alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FRMTYPE_VIEW:
|
||||
/* change of schema is not allowed */
|
||||
if (strcmp(ren_table->db, new_db))
|
||||
my_error(ER_FORBID_SCHEMA_CHANGE, MYF(0), ren_table->db,
|
||||
new_db);
|
||||
else
|
||||
rc= mysql_rename_view(thd, new_alias, ren_table);
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0); // should never happen
|
||||
case FRMTYPE_ERROR:
|
||||
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
|
||||
break;
|
||||
}
|
||||
if (rc && !skip_error)
|
||||
DBUG_RETURN(1);
|
||||
|
||||
DBUG_RETURN(0);
|
||||
|
||||
}
|
||||
/*
|
||||
Rename all tables in list; Return pointer to wrong entry if something goes
|
||||
wrong. Note that the table_list may be empty!
|
||||
*/
|
||||
|
||||
/*
|
||||
Rename tables/views in the list
|
||||
|
||||
SYNPOSIS
|
||||
rename_tables()
|
||||
thd Thread handle
|
||||
table_list List of tables to rename
|
||||
skip_error Whether to skip errors
|
||||
|
||||
DESCRIPTION
|
||||
Take a table/view name from and odd list element and rename it to a
|
||||
the name taken from list element+1. Note that the table_list may be
|
||||
empty.
|
||||
|
||||
RETURN
|
||||
false Ok
|
||||
true rename failed
|
||||
*/
|
||||
|
||||
static TABLE_LIST *
|
||||
rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
|
||||
{
|
||||
TABLE_LIST *ren_table,*new_table;
|
||||
frm_type_enum frm_type;
|
||||
db_type table_type;
|
||||
TABLE_LIST *ren_table,*new_table, *tmp_table;
|
||||
|
||||
DBUG_ENTER("rename_tables");
|
||||
|
||||
for (ren_table= table_list; ren_table; ren_table= new_table->next_local)
|
||||
{
|
||||
int rc= 1;
|
||||
char name[FN_REFLEN];
|
||||
const char *new_alias, *old_alias;
|
||||
|
||||
new_table= ren_table->next_local;
|
||||
if (lower_case_table_names == 2)
|
||||
{
|
||||
old_alias= ren_table->alias;
|
||||
new_alias= new_table->alias;
|
||||
}
|
||||
else
|
||||
{
|
||||
old_alias= ren_table->table_name;
|
||||
new_alias= new_table->table_name;
|
||||
}
|
||||
sprintf(name,"%s/%s/%s%s",mysql_data_home,
|
||||
new_table->db, new_alias, reg_ext);
|
||||
unpack_filename(name, name);
|
||||
if (!access(name,F_OK))
|
||||
{
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
|
||||
DBUG_RETURN(ren_table); // This can't be skipped
|
||||
}
|
||||
sprintf(name,"%s/%s/%s%s",mysql_data_home,
|
||||
ren_table->db, old_alias,
|
||||
reg_ext);
|
||||
unpack_filename(name, name);
|
||||
|
||||
frm_type= mysql_frm_type(thd, name, &table_type);
|
||||
switch (frm_type)
|
||||
{
|
||||
case FRMTYPE_TABLE:
|
||||
{
|
||||
if (table_type == DB_TYPE_UNKNOWN)
|
||||
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
|
||||
else
|
||||
{
|
||||
if (!(rc= mysql_rename_table(table_type, ren_table->db, old_alias,
|
||||
new_table->db, new_alias)))
|
||||
{
|
||||
if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db,
|
||||
old_alias,
|
||||
new_table->db,
|
||||
new_alias)))
|
||||
{
|
||||
/*
|
||||
We've succeeded in renaming table's .frm and in updating
|
||||
corresponding handler data, but have failed to update table's
|
||||
triggers appropriately. So let us revert operations on .frm
|
||||
and handler's data and report about failure to rename table.
|
||||
*/
|
||||
(void) mysql_rename_table(table_type, new_table->db, new_alias,
|
||||
ren_table->db, old_alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FRMTYPE_VIEW:
|
||||
/* change of schema is not allowed */
|
||||
if (strcmp(ren_table->db, new_table->db))
|
||||
my_error(ER_FORBID_SCHEMA_CHANGE, MYF(0), ren_table->db,
|
||||
new_table->db);
|
||||
else
|
||||
rc= mysql_rename_view(thd, new_alias, ren_table);
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0); // should never happen
|
||||
case FRMTYPE_ERROR:
|
||||
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
|
||||
break;
|
||||
}
|
||||
if (rc && !skip_error)
|
||||
if (do_rename(thd, ren_table, new_table->db, new_table->table_name,
|
||||
new_table->alias, skip_error))
|
||||
DBUG_RETURN(ren_table);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
|
|
|
@ -35,14 +35,17 @@ const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
|
|||
"index_merge"
|
||||
};
|
||||
|
||||
struct st_sargable_param;
|
||||
|
||||
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
|
||||
static bool make_join_statistics(JOIN *join, TABLE_LIST *leaves, COND *conds,
|
||||
DYNAMIC_ARRAY *keyuse);
|
||||
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
|
||||
JOIN_TAB *join_tab,
|
||||
JOIN_TAB *join_tab,
|
||||
uint tables, COND *conds,
|
||||
COND_EQUAL *cond_equal,
|
||||
table_map table_map, SELECT_LEX *select_lex);
|
||||
table_map table_map, SELECT_LEX *select_lex,
|
||||
st_sargable_param **sargables);
|
||||
static int sort_keyuse(KEYUSE *a,KEYUSE *b);
|
||||
static void set_position(JOIN *join,uint index,JOIN_TAB *table,KEYUSE *key);
|
||||
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
||||
|
@ -1375,12 +1378,13 @@ JOIN::exec()
|
|||
thd->examined_row_count= 0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
/*
|
||||
don't reset the found rows count if there're no tables
|
||||
as FOUND_ROWS() may be called.
|
||||
*/
|
||||
/*
|
||||
Don't reset the found rows count if there're no tables as
|
||||
FOUND_ROWS() may be called. Never reset the examined row count here.
|
||||
It must be accumulated from all join iterations of all join parts.
|
||||
*/
|
||||
if (tables)
|
||||
thd->limit_found_rows= thd->examined_row_count= 0;
|
||||
thd->limit_found_rows= 0;
|
||||
|
||||
if (zero_result_cause)
|
||||
{
|
||||
|
@ -1410,7 +1414,8 @@ JOIN::exec()
|
|||
simple_order= simple_group;
|
||||
skip_sort_order= 0;
|
||||
}
|
||||
if (order &&
|
||||
if (order &&
|
||||
(order != group_list || !(select_options & SELECT_BIG_RESULT)) &&
|
||||
(const_tables == tables ||
|
||||
((simple_order || skip_sort_order) &&
|
||||
test_if_skip_sort_order(&join_tab[const_tables], order,
|
||||
|
@ -1428,6 +1433,12 @@ JOIN::exec()
|
|||
List<Item> *curr_all_fields= &all_fields;
|
||||
List<Item> *curr_fields_list= &fields_list;
|
||||
TABLE *curr_tmp_table= 0;
|
||||
/*
|
||||
Initialize examined rows here because the values from all join parts
|
||||
must be accumulated in examined_row_count. Hence every join
|
||||
iteration must count from zero.
|
||||
*/
|
||||
curr_join->examined_rows= 0;
|
||||
|
||||
if ((curr_join->select_lex->options & OPTION_SCHEMA_TABLE) &&
|
||||
get_schema_tables_result(curr_join))
|
||||
|
@ -1585,6 +1596,7 @@ JOIN::exec()
|
|||
{
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
sortorder= curr_join->sortorder;
|
||||
}
|
||||
|
||||
thd->proc_info="Copying to group table";
|
||||
|
@ -1794,6 +1806,7 @@ JOIN::exec()
|
|||
(select_options & OPTION_FOUND_ROWS ?
|
||||
HA_POS_ERROR : unit->select_limit_cnt)))
|
||||
DBUG_VOID_RETURN;
|
||||
sortorder= curr_join->sortorder;
|
||||
}
|
||||
}
|
||||
/* XXX: When can we have here thd->net.report_error not zero? */
|
||||
|
@ -1834,9 +1847,12 @@ JOIN::exec()
|
|||
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
|
||||
error= do_select(curr_join, curr_fields_list, NULL, procedure);
|
||||
thd->limit_found_rows= curr_join->send_records;
|
||||
thd->examined_row_count= curr_join->examined_rows;
|
||||
}
|
||||
|
||||
/* Accumulate the counts from all join iterations of all join parts. */
|
||||
thd->examined_row_count+= curr_join->examined_rows;
|
||||
DBUG_PRINT("counts", ("thd->examined_row_count: %lu",
|
||||
(ulong) thd->examined_row_count));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
@ -2052,6 +2068,19 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
|
|||
DBUG_RETURN(HA_POS_ERROR); /* This shouldn't happend */
|
||||
}
|
||||
|
||||
/*
|
||||
This structure is used to collect info on potentially sargable
|
||||
predicates in order to check whether they become sargable after
|
||||
reading const tables.
|
||||
We form a bitmap of indexes that can be used for sargable predicates.
|
||||
Only such indexes are involved in range analysis.
|
||||
*/
|
||||
typedef struct st_sargable_param
|
||||
{
|
||||
Field *field; /* field against which to check sargability */
|
||||
Item **arg_value; /* values of potential keys for lookups */
|
||||
uint num_values; /* number of values in the above array */
|
||||
} SARGABLE_PARAM;
|
||||
|
||||
/*
|
||||
Calculate the best possible join and initialize the join structure
|
||||
|
@ -2074,6 +2103,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|||
JOIN_TAB *stat,*stat_end,*s,**stat_ref;
|
||||
KEYUSE *keyuse,*start_keyuse;
|
||||
table_map outer_join=0;
|
||||
SARGABLE_PARAM *sargables= 0;
|
||||
JOIN_TAB *stat_vector[MAX_TABLES+1];
|
||||
DBUG_ENTER("make_join_statistics");
|
||||
|
||||
|
@ -2195,7 +2225,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|||
if (conds || outer_join)
|
||||
if (update_ref_and_keys(join->thd, keyuse_array, stat, join->tables,
|
||||
conds, join->cond_equal,
|
||||
~outer_join, join->select_lex))
|
||||
~outer_join, join->select_lex, &sargables))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
/* Read tables with 0 or 1 rows (system tables) */
|
||||
|
@ -2345,6 +2375,26 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|||
}
|
||||
} while (join->const_table_map & found_ref && ref_changed);
|
||||
|
||||
/*
|
||||
Update info on indexes that can be used for search lookups as
|
||||
reading const tables may has added new sargable predicates.
|
||||
*/
|
||||
if (const_count && sargables)
|
||||
{
|
||||
for( ; sargables->field ; sargables++)
|
||||
{
|
||||
Field *field= sargables->field;
|
||||
JOIN_TAB *stat= field->table->reginfo.join_tab;
|
||||
key_map possible_keys= field->key_start;
|
||||
possible_keys.intersect(field->table->keys_in_use_for_query);
|
||||
bool is_const= 1;
|
||||
for (uint i=0; i< sargables->num_values; i++)
|
||||
is_const&= sargables->arg_value[i]->const_item();
|
||||
if (is_const)
|
||||
stat[0].const_keys.merge(possible_keys);
|
||||
}
|
||||
}
|
||||
|
||||
/* Calc how many (possible) matched records in each table */
|
||||
|
||||
for (s=stat ; s < stat_end ; s++)
|
||||
|
@ -2604,6 +2654,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
|
|||
eq_func True if we used =, <=> or IS NULL
|
||||
value Value used for comparison with field
|
||||
usable_tables Tables which can be used for key optimization
|
||||
sargables IN/OUT Array of found sargable candidates
|
||||
|
||||
NOTES
|
||||
If we are doing a NOT NULL comparison on a NOT NULL field in a outer join
|
||||
|
@ -2615,8 +2666,8 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
|
|||
|
||||
static void
|
||||
add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
|
||||
Field *field, bool eq_func, Item **value, uint num_values,
|
||||
table_map usable_tables)
|
||||
Field *field, bool eq_func, Item **value, uint num_values,
|
||||
table_map usable_tables, SARGABLE_PARAM **sargables)
|
||||
{
|
||||
uint exists_optimize= 0;
|
||||
if (!(field->flags & PART_KEY_FLAG))
|
||||
|
@ -2672,6 +2723,19 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
|
|||
is_const&= value[i]->const_item();
|
||||
if (is_const)
|
||||
stat[0].const_keys.merge(possible_keys);
|
||||
else if (!eq_func)
|
||||
{
|
||||
/*
|
||||
Save info to be able check whether this predicate can be
|
||||
considered as sargable for range analisis after reading const tables.
|
||||
We do not save info about equalities as update_const_equal_items
|
||||
will take care of updating info on keys from sargable equalities.
|
||||
*/
|
||||
(*sargables)--;
|
||||
(*sargables)->field= field;
|
||||
(*sargables)->arg_value= value;
|
||||
(*sargables)->num_values= num_values;
|
||||
}
|
||||
/*
|
||||
We can't always use indexes when comparing a string index to a
|
||||
number. cmp_type() is checked to allow compare of dates to numbers.
|
||||
|
@ -2762,6 +2826,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
|
|||
value Value used for comparison with field
|
||||
Is NULL for BETWEEN and IN
|
||||
usable_tables Tables which can be used for key optimization
|
||||
sargables IN/OUT Array of found sargable candidates
|
||||
|
||||
NOTES
|
||||
If field items f1 and f2 belong to the same multiple equality and
|
||||
|
@ -2775,11 +2840,12 @@ static void
|
|||
add_key_equal_fields(KEY_FIELD **key_fields, uint and_level,
|
||||
Item_func *cond, Item_field *field_item,
|
||||
bool eq_func, Item **val,
|
||||
uint num_values, table_map usable_tables)
|
||||
uint num_values, table_map usable_tables,
|
||||
SARGABLE_PARAM **sargables)
|
||||
{
|
||||
Field *field= field_item->field;
|
||||
add_key_field(key_fields, and_level, cond, field,
|
||||
eq_func, val, num_values, usable_tables);
|
||||
eq_func, val, num_values, usable_tables, sargables);
|
||||
Item_equal *item_equal= field_item->item_equal;
|
||||
if (item_equal)
|
||||
{
|
||||
|
@ -2794,7 +2860,8 @@ add_key_equal_fields(KEY_FIELD **key_fields, uint and_level,
|
|||
if (!field->eq(item->field))
|
||||
{
|
||||
add_key_field(key_fields, and_level, cond, item->field,
|
||||
eq_func, val, num_values, usable_tables);
|
||||
eq_func, val, num_values, usable_tables,
|
||||
sargables);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2802,7 +2869,8 @@ add_key_equal_fields(KEY_FIELD **key_fields, uint and_level,
|
|||
|
||||
static void
|
||||
add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
||||
COND *cond, table_map usable_tables)
|
||||
COND *cond, table_map usable_tables,
|
||||
SARGABLE_PARAM **sargables)
|
||||
{
|
||||
if (cond->type() == Item_func::COND_ITEM)
|
||||
{
|
||||
|
@ -2813,20 +2881,20 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|||
{
|
||||
Item *item;
|
||||
while ((item=li++))
|
||||
add_key_fields(key_fields,and_level,item,usable_tables);
|
||||
add_key_fields(key_fields,and_level,item,usable_tables,sargables);
|
||||
for (; org_key_fields != *key_fields ; org_key_fields++)
|
||||
org_key_fields->level= *and_level;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*and_level)++;
|
||||
add_key_fields(key_fields,and_level,li++,usable_tables);
|
||||
add_key_fields(key_fields,and_level,li++,usable_tables,sargables);
|
||||
Item *item;
|
||||
while ((item=li++))
|
||||
{
|
||||
KEY_FIELD *start_key_fields= *key_fields;
|
||||
(*and_level)++;
|
||||
add_key_fields(key_fields,and_level,item,usable_tables);
|
||||
add_key_fields(key_fields,and_level,item,usable_tables,sargables);
|
||||
*key_fields=merge_key_fields(org_key_fields,start_key_fields,
|
||||
*key_fields,++(*and_level));
|
||||
}
|
||||
|
@ -2857,9 +2925,9 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|||
cond_func->argument_count() != 2);
|
||||
add_key_equal_fields(key_fields, *and_level, cond_func,
|
||||
(Item_field*) (cond_func->key_item()->real_item()),
|
||||
0, values,
|
||||
0, values,
|
||||
cond_func->argument_count()-1,
|
||||
usable_tables);
|
||||
usable_tables, sargables);
|
||||
}
|
||||
if (cond_func->functype() == Item_func::BETWEEN)
|
||||
{
|
||||
|
@ -2873,7 +2941,8 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|||
{
|
||||
field_item= (Item_field *) (cond_func->arguments()[i]->real_item());
|
||||
add_key_equal_fields(key_fields, *and_level, cond_func,
|
||||
field_item, 0, values, 1, usable_tables);
|
||||
field_item, 0, values, 1, usable_tables,
|
||||
sargables);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2890,7 +2959,8 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|||
add_key_equal_fields(key_fields, *and_level, cond_func,
|
||||
(Item_field*) (cond_func->arguments()[0])->real_item(),
|
||||
equal_func,
|
||||
cond_func->arguments()+1, 1, usable_tables);
|
||||
cond_func->arguments()+1, 1, usable_tables,
|
||||
sargables);
|
||||
}
|
||||
if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
|
||||
cond_func->functype() != Item_func::LIKE_FUNC &&
|
||||
|
@ -2899,7 +2969,8 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|||
add_key_equal_fields(key_fields, *and_level, cond_func,
|
||||
(Item_field*) (cond_func->arguments()[1])->real_item(),
|
||||
equal_func,
|
||||
cond_func->arguments(),1,usable_tables);
|
||||
cond_func->arguments(),1,usable_tables,
|
||||
sargables);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -2914,7 +2985,7 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|||
add_key_equal_fields(key_fields, *and_level, cond_func,
|
||||
(Item_field*) (cond_func->arguments()[0])->real_item(),
|
||||
cond_func->functype() == Item_func::ISNULL_FUNC,
|
||||
&tmp, 1, usable_tables);
|
||||
&tmp, 1, usable_tables, sargables);
|
||||
}
|
||||
break;
|
||||
case Item_func::OPTIMIZE_EQUAL:
|
||||
|
@ -2932,7 +3003,7 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|||
while ((item= it++))
|
||||
{
|
||||
add_key_field(key_fields, *and_level, cond_func, item->field,
|
||||
TRUE, &const_item, 1, usable_tables);
|
||||
TRUE, &const_item, 1, usable_tables, sargables);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2952,7 +3023,8 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|||
if (!field->eq(item->field))
|
||||
{
|
||||
add_key_field(key_fields, *and_level, cond_func, field,
|
||||
TRUE, (Item **) &item, 1, usable_tables);
|
||||
TRUE, (Item **) &item, 1, usable_tables,
|
||||
sargables);
|
||||
}
|
||||
}
|
||||
it.rewind();
|
||||
|
@ -3103,6 +3175,7 @@ sort_keyuse(KEYUSE *a,KEYUSE *b)
|
|||
nested_join_table IN Nested join pseudo-table to process
|
||||
end INOUT End of the key field array
|
||||
and_level INOUT And-level
|
||||
sargables IN/OUT Array of found sargable candidates
|
||||
|
||||
DESCRIPTION
|
||||
This function populates KEY_FIELD array with entries generated from the
|
||||
|
@ -3126,7 +3199,8 @@ sort_keyuse(KEYUSE *a,KEYUSE *b)
|
|||
*/
|
||||
|
||||
static void add_key_fields_for_nj(TABLE_LIST *nested_join_table,
|
||||
KEY_FIELD **end, uint *and_level)
|
||||
KEY_FIELD **end, uint *and_level,
|
||||
SARGABLE_PARAM **sargables)
|
||||
{
|
||||
List_iterator<TABLE_LIST> li(nested_join_table->nested_join->join_list);
|
||||
table_map tables= 0;
|
||||
|
@ -3136,12 +3210,12 @@ static void add_key_fields_for_nj(TABLE_LIST *nested_join_table,
|
|||
while ((table= li++))
|
||||
{
|
||||
if (table->nested_join)
|
||||
add_key_fields_for_nj(table, end, and_level);
|
||||
add_key_fields_for_nj(table, end, and_level, sargables);
|
||||
else
|
||||
if (!table->on_expr)
|
||||
tables |= table->table->map;
|
||||
}
|
||||
add_key_fields(end, and_level, nested_join_table->on_expr, tables);
|
||||
add_key_fields(end, and_level, nested_join_table->on_expr, tables, sargables);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3156,9 +3230,10 @@ static void add_key_fields_for_nj(TABLE_LIST *nested_join_table,
|
|||
tables Number of tables in join
|
||||
cond WHERE condition (note that the function analyzes
|
||||
join_tab[i]->on_expr too)
|
||||
normal_tables tables not inner w.r.t some outer join (ones for which
|
||||
normal_tables Tables not inner w.r.t some outer join (ones for which
|
||||
we can make ref access based the WHERE clause)
|
||||
select_lex current SELECT
|
||||
sargables OUT Array of found sargable candidates
|
||||
|
||||
RETURN
|
||||
0 - OK
|
||||
|
@ -3167,27 +3242,55 @@ static void add_key_fields_for_nj(TABLE_LIST *nested_join_table,
|
|||
|
||||
static bool
|
||||
update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
||||
uint tables, COND *cond, COND_EQUAL *cond_equal,
|
||||
table_map normal_tables, SELECT_LEX *select_lex)
|
||||
uint tables, COND *cond, COND_EQUAL *cond_equal,
|
||||
table_map normal_tables, SELECT_LEX *select_lex,
|
||||
SARGABLE_PARAM **sargables)
|
||||
{
|
||||
uint and_level,i,found_eq_constant;
|
||||
KEY_FIELD *key_fields, *end, *field;
|
||||
uint sz;
|
||||
uint m= 1;
|
||||
|
||||
if (cond_equal && cond_equal->max_members)
|
||||
m= cond_equal->max_members;
|
||||
|
||||
if (!(key_fields=(KEY_FIELD*)
|
||||
thd->alloc(sizeof(key_fields[0])*
|
||||
(thd->lex->current_select->cond_count+1)*2*m)))
|
||||
|
||||
/*
|
||||
We use the same piece of memory to store both KEY_FIELD
|
||||
and SARGABLE_PARAM structure.
|
||||
KEY_FIELD values are placed at the beginning this memory
|
||||
while SARGABLE_PARAM values are put at the end.
|
||||
All predicates that are used to fill arrays of KEY_FIELD
|
||||
and SARGABLE_PARAM structures have at most 2 arguments
|
||||
except BETWEEN predicates that have 3 arguments and
|
||||
IN predicates.
|
||||
This any predicate if it's not BETWEEN/IN can be used
|
||||
directly to fill at most 2 array elements, either of KEY_FIELD
|
||||
or SARGABLE_PARAM type. For a BETWEEN predicate 3 elements
|
||||
can be filled as this predicate is considered as
|
||||
saragable with respect to each of its argument.
|
||||
An IN predicate can require at most 1 element as currently
|
||||
it is considered as sargable only for its first argument.
|
||||
Multiple equality can add elements that are filled after
|
||||
substitution of field arguments by equal fields. There
|
||||
can be not more than cond_equal->max_members such substitutions.
|
||||
*/
|
||||
sz= max(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))*
|
||||
(((thd->lex->current_select->cond_count+1)*2 +
|
||||
thd->lex->current_select->between_count)*m+1);
|
||||
if (!(key_fields=(KEY_FIELD*) thd->alloc(sz)))
|
||||
return TRUE; /* purecov: inspected */
|
||||
and_level= 0;
|
||||
field= end= key_fields;
|
||||
*sargables= (SARGABLE_PARAM *) key_fields +
|
||||
(sz - sizeof((*sargables)[0].field))/sizeof(SARGABLE_PARAM);
|
||||
/* set a barrier for the array of SARGABLE_PARAM */
|
||||
(*sargables)[0].field= 0;
|
||||
|
||||
if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64))
|
||||
return TRUE;
|
||||
if (cond)
|
||||
{
|
||||
add_key_fields(&end,&and_level,cond,normal_tables);
|
||||
add_key_fields(&end,&and_level,cond,normal_tables,sargables);
|
||||
for (; field != end ; field++)
|
||||
{
|
||||
add_key_part(keyuse,field);
|
||||
|
@ -3210,7 +3313,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
|||
*/
|
||||
if (*join_tab[i].on_expr_ref)
|
||||
add_key_fields(&end,&and_level,*join_tab[i].on_expr_ref,
|
||||
join_tab[i].table->map);
|
||||
join_tab[i].table->map,sargables);
|
||||
}
|
||||
|
||||
/* Process ON conditions for the nested joins */
|
||||
|
@ -3220,7 +3323,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
|||
while ((table= li++))
|
||||
{
|
||||
if (table->nested_join)
|
||||
add_key_fields_for_nj(table, &end, &and_level);
|
||||
add_key_fields_for_nj(table, &end, &and_level, sargables);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4960,9 +5063,28 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
|
|||
JOIN_TAB *join_tab;
|
||||
DBUG_ENTER("make_simple_join");
|
||||
|
||||
if (!(tableptr=(TABLE**) join->thd->alloc(sizeof(TABLE*))) ||
|
||||
!(join_tab=(JOIN_TAB*) join->thd->alloc(sizeof(JOIN_TAB))))
|
||||
DBUG_RETURN(TRUE);
|
||||
/*
|
||||
Reuse TABLE * and JOIN_TAB if already allocated by a previous call
|
||||
to this function through JOIN::exec (may happen for sub-queries).
|
||||
*/
|
||||
if (!join->table_reexec)
|
||||
{
|
||||
if (!(join->table_reexec= (TABLE**) join->thd->alloc(sizeof(TABLE*))))
|
||||
DBUG_RETURN(TRUE); /* purecov: inspected */
|
||||
if (join->tmp_join)
|
||||
join->tmp_join->table_reexec= join->table_reexec;
|
||||
}
|
||||
if (!join->join_tab_reexec)
|
||||
{
|
||||
if (!(join->join_tab_reexec=
|
||||
(JOIN_TAB*) join->thd->alloc(sizeof(JOIN_TAB))))
|
||||
DBUG_RETURN(TRUE); /* purecov: inspected */
|
||||
if (join->tmp_join)
|
||||
join->tmp_join->join_tab_reexec= join->join_tab_reexec;
|
||||
}
|
||||
tableptr= join->table_reexec;
|
||||
join_tab= join->join_tab_reexec;
|
||||
|
||||
join->join_tab=join_tab;
|
||||
join->table=tableptr; tableptr[0]=tmp_table;
|
||||
join->tables=1;
|
||||
|
@ -7344,7 +7466,22 @@ static void update_const_equal_items(COND *cond, JOIN_TAB *tab)
|
|||
((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
|
||||
{
|
||||
Item_equal *item_equal= (Item_equal *) cond;
|
||||
bool contained_const= item_equal->get_const() != NULL;
|
||||
item_equal->update_const();
|
||||
if (!contained_const && item_equal->get_const())
|
||||
{
|
||||
/* Update keys for range analysis */
|
||||
Item_equal_iterator it(*item_equal);
|
||||
Item_field *item_field;
|
||||
while ((item_field= it++))
|
||||
{
|
||||
Field *field= item_field->field;
|
||||
JOIN_TAB *stat= field->table->reginfo.join_tab;
|
||||
key_map possible_keys= field->key_start;
|
||||
possible_keys.intersect(field->table->keys_in_use_for_query);
|
||||
stat[0].const_keys.merge(possible_keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10141,6 +10278,8 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
|
|||
*/
|
||||
join->examined_rows++;
|
||||
join->thd->row_count++;
|
||||
DBUG_PRINT("counts", ("join->examined_rows++: %lu",
|
||||
(ulong) join->examined_rows));
|
||||
|
||||
if (found)
|
||||
{
|
||||
|
@ -11993,7 +12132,6 @@ static int
|
|||
create_sort_index(THD *thd, JOIN *join, ORDER *order,
|
||||
ha_rows filesort_limit, ha_rows select_limit)
|
||||
{
|
||||
SORT_FIELD *sortorder;
|
||||
uint length;
|
||||
ha_rows examined_rows;
|
||||
TABLE *table;
|
||||
|
@ -12007,11 +12145,18 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
|
|||
table= tab->table;
|
||||
select= tab->select;
|
||||
|
||||
if (test_if_skip_sort_order(tab,order,select_limit,0))
|
||||
/*
|
||||
When there is SQL_BIG_RESULT do not sort using index for GROUP BY,
|
||||
and thus force sorting on disk.
|
||||
*/
|
||||
if ((order != join->group_list ||
|
||||
!(join->select_options & SELECT_BIG_RESULT)) &&
|
||||
test_if_skip_sort_order(tab,order,select_limit,0))
|
||||
DBUG_RETURN(0);
|
||||
if (!(sortorder=make_unireg_sortorder(order,&length)))
|
||||
if (!(join->sortorder=
|
||||
make_unireg_sortorder(order,&length,join->sortorder)))
|
||||
goto err; /* purecov: inspected */
|
||||
/* It's not fatal if the following alloc fails */
|
||||
|
||||
table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
|
||||
MYF(MY_WME | MY_ZEROFILL));
|
||||
table->status=0; // May be wrong if quick_select
|
||||
|
@ -12056,7 +12201,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
|
|||
|
||||
if (table->s->tmp_table)
|
||||
table->file->info(HA_STATUS_VARIABLE); // Get record count
|
||||
table->sort.found_records=filesort(thd, table,sortorder, length,
|
||||
table->sort.found_records=filesort(thd, table,join->sortorder, length,
|
||||
select, filesort_limit, &examined_rows);
|
||||
tab->records= table->sort.found_records; // For SQL_CALC_ROWS
|
||||
if (select)
|
||||
|
@ -12403,7 +12548,8 @@ err:
|
|||
}
|
||||
|
||||
|
||||
SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length)
|
||||
SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length,
|
||||
SORT_FIELD *sortorder)
|
||||
{
|
||||
uint count;
|
||||
SORT_FIELD *sort,*pos;
|
||||
|
@ -12412,7 +12558,9 @@ SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length)
|
|||
count=0;
|
||||
for (ORDER *tmp = order; tmp; tmp=tmp->next)
|
||||
count++;
|
||||
pos=sort=(SORT_FIELD*) sql_alloc(sizeof(SORT_FIELD)*(count+1));
|
||||
if (!sortorder)
|
||||
sortorder= (SORT_FIELD*) sql_alloc(sizeof(SORT_FIELD)*(count+1));
|
||||
pos=sort=sortorder;
|
||||
if (!pos)
|
||||
return 0;
|
||||
|
||||
|
@ -13525,7 +13673,19 @@ bool JOIN::alloc_func_list()
|
|||
disctinct->group_by optimization
|
||||
*/
|
||||
if (select_distinct)
|
||||
{
|
||||
group_parts+= fields_list.elements;
|
||||
/*
|
||||
If the ORDER clause is specified then it's possible that
|
||||
it also will be optimized, so reserve space for it too
|
||||
*/
|
||||
if (order)
|
||||
{
|
||||
ORDER *ord;
|
||||
for (ord= order; ord; ord= ord->next)
|
||||
group_parts++;
|
||||
}
|
||||
}
|
||||
|
||||
/* This must use calloc() as rollup_make_fields depends on this */
|
||||
sum_funcs= (Item_sum**) thd->calloc(sizeof(Item_sum**) * (func_count+1) +
|
||||
|
@ -14008,12 +14168,17 @@ bool JOIN::rollup_init()
|
|||
while ((item= it++))
|
||||
{
|
||||
ORDER *group_tmp;
|
||||
bool found_in_group= 0;
|
||||
|
||||
for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next)
|
||||
{
|
||||
if (*group_tmp->item == item)
|
||||
{
|
||||
item->maybe_null= 1;
|
||||
found_in_group= 1;
|
||||
}
|
||||
}
|
||||
if (item->type() == Item::FUNC_ITEM)
|
||||
if (item->type() == Item::FUNC_ITEM && !found_in_group)
|
||||
{
|
||||
bool changed= FALSE;
|
||||
if (change_group_ref(thd, (Item_func *) item, group_list, &changed))
|
||||
|
|
|
@ -282,6 +282,18 @@ public:
|
|||
bool union_part; // this subselect is part of union
|
||||
bool optimized; // flag to avoid double optimization in EXPLAIN
|
||||
|
||||
/*
|
||||
storage for caching buffers allocated during query execution.
|
||||
These buffers allocations need to be cached as the thread memory pool is
|
||||
cleared only at the end of the execution of the whole query and not caching
|
||||
allocations that occur in repetition at execution time will result in
|
||||
excessive memory usage.
|
||||
*/
|
||||
SORT_FIELD *sortorder; // make_unireg_sortorder()
|
||||
TABLE **table_reexec; // make_simple_join()
|
||||
JOIN_TAB *join_tab_reexec; // make_simple_join()
|
||||
/* end of allocation caching storage */
|
||||
|
||||
JOIN(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
|
||||
select_result *result_arg)
|
||||
:fields_list(fields_arg)
|
||||
|
@ -307,6 +319,9 @@ public:
|
|||
examined_rows= 0;
|
||||
exec_tmp_table1= 0;
|
||||
exec_tmp_table2= 0;
|
||||
sortorder= 0;
|
||||
table_reexec= 0;
|
||||
join_tab_reexec= 0;
|
||||
thd= thd_arg;
|
||||
sum_funcs= sum_funcs2= 0;
|
||||
procedure= 0;
|
||||
|
|
|
@ -3155,9 +3155,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
|||
ha_rows copied,deleted;
|
||||
ulonglong next_insert_id;
|
||||
uint db_create_options, used_fields;
|
||||
enum db_type old_db_type,new_db_type;
|
||||
enum db_type old_db_type, new_db_type, table_type;
|
||||
bool need_copy_table;
|
||||
bool no_table_reopen= FALSE, varchar= FALSE;
|
||||
frm_type_enum frm_type;
|
||||
DBUG_ENTER("mysql_alter_table");
|
||||
|
||||
thd->proc_info="init";
|
||||
|
@ -3176,6 +3177,51 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
|||
/* Conditionally writes to binlog. */
|
||||
DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list,
|
||||
alter_info->tablespace_op));
|
||||
sprintf(new_name_buff,"%s/%s/%s%s",mysql_data_home, db, table_name, reg_ext);
|
||||
unpack_filename(new_name_buff, new_name_buff);
|
||||
if (lower_case_table_names != 2)
|
||||
my_casedn_str(files_charset_info, new_name_buff);
|
||||
frm_type= mysql_frm_type(thd, new_name_buff, &table_type);
|
||||
/* Rename a view */
|
||||
if (frm_type == FRMTYPE_VIEW && !(alter_info->flags & ~ALTER_RENAME))
|
||||
{
|
||||
/*
|
||||
Avoid problems with a rename on a table that we have locked or
|
||||
if the user is trying to to do this in a transcation context
|
||||
*/
|
||||
|
||||
if (thd->locked_tables || thd->active_transaction())
|
||||
{
|
||||
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
|
||||
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
if (wait_if_global_read_lock(thd,0,1))
|
||||
DBUG_RETURN(1);
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
if (lock_table_names(thd, table_list))
|
||||
goto view_err;
|
||||
|
||||
error=0;
|
||||
if (!do_rename(thd, table_list, new_db, new_name, new_name, 1))
|
||||
{
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error();
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
send_ok(thd);
|
||||
}
|
||||
|
||||
unlock_table_names(thd, table_list, (TABLE_LIST*) 0);
|
||||
|
||||
view_err:
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
start_waiting_global_read_lock(thd);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
|
@ -4051,7 +4097,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
|
|||
if (thd->lex->select_lex.setup_ref_array(thd, order_num) ||
|
||||
setup_order(thd, thd->lex->select_lex.ref_pointer_array,
|
||||
&tables, fields, all_fields, order) ||
|
||||
!(sortorder=make_unireg_sortorder(order, &length)) ||
|
||||
!(sortorder=make_unireg_sortorder(order, &length, NULL)) ||
|
||||
(from->sort.found_records = filesort(thd, from, sortorder, length,
|
||||
(SQL_SELECT *) 0, HA_POS_ERROR,
|
||||
&examined_rows)) ==
|
||||
|
|
|
@ -311,7 +311,7 @@ int mysql_update(THD *thd,
|
|||
|
||||
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
|
||||
MYF(MY_FAE | MY_ZEROFILL));
|
||||
if (!(sortorder=make_unireg_sortorder(order, &length)) ||
|
||||
if (!(sortorder=make_unireg_sortorder(order, &length, NULL)) ||
|
||||
(table->sort.found_records = filesort(thd, table, sortorder, length,
|
||||
select, limit,
|
||||
&examined_rows))
|
||||
|
|
21
sql/table.cc
21
sql/table.cc
|
@ -468,7 +468,21 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
|
|||
count)))
|
||||
goto err;
|
||||
for (count= 0; count < interval->count; count++)
|
||||
interval->type_lengths[count]= strlen(interval->type_names[count]);
|
||||
{
|
||||
char *val= (char*) interval->type_names[count];
|
||||
interval->type_lengths[count]= strlen(val);
|
||||
/*
|
||||
Replace all ',' symbols with NAMES_SEP_CHAR.
|
||||
See the comment in unireg.cc, pack_fields() function
|
||||
for details.
|
||||
*/
|
||||
for (uint cnt= 0 ; cnt < interval->type_lengths[count] ; cnt++)
|
||||
{
|
||||
char c= val[cnt];
|
||||
if (c == ',')
|
||||
val[cnt]= NAMES_SEP_CHAR;
|
||||
}
|
||||
}
|
||||
interval->type_lengths[count]= 0;
|
||||
}
|
||||
}
|
||||
|
@ -1963,12 +1977,13 @@ bool st_table_list::prep_where(THD *thd, Item **conds,
|
|||
this expression will not be moved to WHERE condition (i.e. will
|
||||
be clean correctly for PS/SP)
|
||||
*/
|
||||
tbl->on_expr= and_conds(tbl->on_expr, where);
|
||||
tbl->on_expr= and_conds(tbl->on_expr,
|
||||
where->copy_andor_structure(thd));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tbl == 0)
|
||||
*conds= and_conds(*conds, where);
|
||||
*conds= and_conds(*conds, where->copy_andor_structure(thd));
|
||||
if (arena)
|
||||
thd->restore_active_arena(arena, &backup);
|
||||
where_processed= TRUE;
|
||||
|
|
|
@ -718,6 +718,21 @@ static bool pack_fields(File file, List<create_field> &create_fields,
|
|||
tmp.append(NAMES_SEP_CHAR);
|
||||
for (const char **pos=field->interval->type_names ; *pos ; pos++)
|
||||
{
|
||||
char *val= (char*) *pos;
|
||||
uint str_len= strlen(val);
|
||||
/*
|
||||
Note, hack: in old frm NAMES_SEP_CHAR is used to separate
|
||||
names in the interval (ENUM/SET). To allow names to contain
|
||||
NAMES_SEP_CHAR, we replace it with a comma before writing frm.
|
||||
Backward conversion is done during frm file opening,
|
||||
See table.cc, openfrm() function
|
||||
*/
|
||||
for (uint cnt= 0 ; cnt < str_len ; cnt++)
|
||||
{
|
||||
char c= val[cnt];
|
||||
if (c == NAMES_SEP_CHAR)
|
||||
val[cnt]= ',';
|
||||
}
|
||||
tmp.append(*pos);
|
||||
tmp.append(NAMES_SEP_CHAR);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ typedef struct charset_info_st
|
|||
uint strxfrm_multiply;
|
||||
uint mbminlen;
|
||||
uint mbmaxlen;
|
||||
char max_sort_char; /* For LIKE optimization */
|
||||
uint16 max_sort_char; /* For LIKE optimization */
|
||||
|
||||
MY_CHARSET_HANDLER *cset;
|
||||
MY_COLLATION_HANDLER *coll;
|
||||
|
@ -134,7 +134,15 @@ Misc fields
|
|||
mbmaxlen - maximum multibyte sequence length.
|
||||
1 for 8bit charsets. Can be also 2 or 3.
|
||||
|
||||
|
||||
max_sort_char - for LIKE range
|
||||
in case of 8bit character sets - native code
|
||||
of maximum character (max_str pad byte);
|
||||
in case of UTF8 and UCS2 - Unicode code of the maximum
|
||||
possible character (usually U+FFFF). This code is
|
||||
converted to multibyte representation (usually 0xEFBFBF)
|
||||
and then used as a pad sequence for max_str.
|
||||
in case of other multibyte character sets -
|
||||
max_str pad byte (usually 0xFF).
|
||||
|
||||
MY_CHARSET_HANDLER
|
||||
==================
|
||||
|
|
|
@ -474,15 +474,35 @@ static void my_hash_sort_mb_bin(CHARSET_INFO *cs __attribute__((unused)),
|
|||
|
||||
|
||||
/*
|
||||
Write max key: create a buffer with multibyte
|
||||
representation of the max_sort_char character,
|
||||
and copy it into max_str in a loop.
|
||||
Fill the given buffer with 'maximum character' for given charset
|
||||
SYNOPSIS
|
||||
pad_max_char()
|
||||
cs Character set
|
||||
str Start of buffer to fill
|
||||
end End of buffer to fill
|
||||
|
||||
DESCRIPTION
|
||||
Write max key:
|
||||
- for non-Unicode character sets:
|
||||
just set to 255.
|
||||
- for Unicode character set (utf-8):
|
||||
create a buffer with multibyte representation of the max_sort_char
|
||||
character, and copy it into max_str in a loop.
|
||||
*/
|
||||
static void pad_max_char(CHARSET_INFO *cs, char *str, char *end)
|
||||
{
|
||||
char buf[10];
|
||||
char buflen= cs->cset->wc_mb(cs, cs->max_sort_char, (uchar*) buf,
|
||||
(uchar*) buf + sizeof(buf));
|
||||
char buflen;
|
||||
|
||||
if (!(cs->state & MY_CS_UNICODE))
|
||||
{
|
||||
bfill(str, end - str, 255);
|
||||
return;
|
||||
}
|
||||
|
||||
buflen= cs->cset->wc_mb(cs, cs->max_sort_char, (uchar*) buf,
|
||||
(uchar*) buf + sizeof(buf));
|
||||
|
||||
DBUG_ASSERT(buflen > 0);
|
||||
do
|
||||
{
|
||||
|
@ -927,7 +947,7 @@ MY_COLLATION_HANDLER my_collation_mb_bin_handler =
|
|||
my_strnncollsp_mb_bin,
|
||||
my_strnxfrm_mb_bin,
|
||||
my_strnxfrmlen_simple,
|
||||
my_like_range_simple,
|
||||
my_like_range_mb,
|
||||
my_wildcmp_mb_bin,
|
||||
my_strcasecmp_mb_bin,
|
||||
my_instr_mb,
|
||||
|
|
|
@ -2612,7 +2612,7 @@ CHARSET_INFO my_charset_utf8_bin=
|
|||
1, /* mbminlen */
|
||||
3, /* mbmaxlen */
|
||||
0, /* min_sort_char */
|
||||
255, /* max_sort_char */
|
||||
0xFFFF, /* max_sort_char */
|
||||
' ', /* pad char */
|
||||
0, /* escape_with_backslash_is_dangerous */
|
||||
&my_charset_utf8_handler,
|
||||
|
|
Loading…
Reference in a new issue