Commit e68bd85b authored by serg@serg.mylan's avatar serg@serg.mylan

merged

parents 2074aeec 19067008
...@@ -20,8 +20,8 @@ ...@@ -20,8 +20,8 @@
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/regex \ INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/regex \
$(openssl_includes) $(openssl_includes)
LIBS = @CLIENT_LIBS@ LIBS = @CLIENT_LIBS@
DEPLIB= ../libmysql/libmysqlclient.la \ DEPLIB= @ndb_mgmclient_libs@ \
@ndb_mgmclient_libs@ ../libmysql/libmysqlclient.la
LDADD = @CLIENT_EXTRA_LDFLAGS@ $(DEPLIB) LDADD = @CLIENT_EXTRA_LDFLAGS@ $(DEPLIB)
bin_PROGRAMS = mysql mysqladmin mysqlcheck mysqlshow \ bin_PROGRAMS = mysql mysqladmin mysqlcheck mysqlshow \
mysqldump mysqlimport mysqltest mysqlbinlog mysqlmanagerc mysqlmanager-pwgen mysqldump mysqlimport mysqltest mysqlbinlog mysqlmanagerc mysqlmanager-pwgen
......
...@@ -102,9 +102,11 @@ static int check_one_key(HP_KEYDEF *keydef, uint keynr, ulong records, ...@@ -102,9 +102,11 @@ static int check_one_key(HP_KEYDEF *keydef, uint keynr, ulong records,
int error; int error;
uint i,found,max_links,seek,links; uint i,found,max_links,seek,links;
uint rec_link; /* Only used with debugging */ uint rec_link; /* Only used with debugging */
uint hash_buckets_found;
HASH_INFO *hash_info; HASH_INFO *hash_info;
error=0; error=0;
hash_buckets_found= 0;
for (i=found=max_links=seek=0 ; i < records ; i++) for (i=found=max_links=seek=0 ; i < records ; i++)
{ {
hash_info=hp_find_hash(&keydef->block,i); hash_info=hp_find_hash(&keydef->block,i);
...@@ -128,21 +130,32 @@ static int check_one_key(HP_KEYDEF *keydef, uint keynr, ulong records, ...@@ -128,21 +130,32 @@ static int check_one_key(HP_KEYDEF *keydef, uint keynr, ulong records,
found++; found++;
} }
if (links > max_links) max_links=links; if (links > max_links) max_links=links;
hash_buckets_found++;
} }
} }
if (found != records) if (found != records)
{ {
DBUG_PRINT("error",("Found %ld of %ld records")); DBUG_PRINT("error",("Found %ld of %ld records", found, records));
error=1;
}
if (keydef->hash_buckets != hash_buckets_found)
{
DBUG_PRINT("error",("Found %ld buckets, stats shows %ld buckets",
hash_buckets_found, keydef->hash_buckets));
error=1; error=1;
} }
DBUG_PRINT("info", DBUG_PRINT("info",
("records: %ld seeks: %d max links: %d hitrate: %.2f", ("records: %ld seeks: %d max links: %d hitrate: %.2f "
"buckets: %d",
records,seek,max_links, records,seek,max_links,
(float) seek / (float) (records ? records : 1))); (float) seek / (float) (records ? records : 1),
hash_buckets_found));
if (print_status) if (print_status)
printf("Key: %d records: %ld seeks: %d max links: %d hitrate: %.2f\n", printf("Key: %d records: %ld seeks: %d max links: %d "
"hitrate: %.2f buckets: %d\n",
keynr, records, seek, max_links, keynr, records, seek, max_links,
(float) seek / (float) (records ? records : 1)); (float) seek / (float) (records ? records : 1),
hash_buckets_found);
return error; return error;
} }
......
...@@ -18,12 +18,19 @@ ...@@ -18,12 +18,19 @@
#include "heapdef.h" #include "heapdef.h"
/* Find record according to record-position */ /*
Find record according to record-position.
The record is located by factoring position number pos into (p_0, p_1, ...)
such that
pos = SUM_i(block->level_info[i].records_under_level * p_i)
{p_0, p_1, ...} serve as indexes to descend the blocks tree.
*/
byte *hp_find_block(HP_BLOCK *block, ulong pos) byte *hp_find_block(HP_BLOCK *block, ulong pos)
{ {
reg1 int i; reg1 int i;
reg3 HP_PTRS *ptr; reg3 HP_PTRS *ptr; /* block base ptr */
for (i=block->levels-1, ptr=block->root ; i > 0 ; i--) for (i=block->levels-1, ptr=block->root ; i > 0 ; i--)
{ {
...@@ -34,8 +41,18 @@ byte *hp_find_block(HP_BLOCK *block, ulong pos) ...@@ -34,8 +41,18 @@ byte *hp_find_block(HP_BLOCK *block, ulong pos)
} }
/* get one new block-of-records. Alloc ptr to block if neaded */ /*
/* Interrupts are stopped to allow ha_panic in interrupts */ Get one new block-of-records. Alloc ptr to block if needed
SYNOPSIS
hp_get_new_block()
block HP_BLOCK tree-like block
alloc_length OUT Amount of memory allocated from the heap
Interrupts are stopped to allow ha_panic in interrupts
RETURN
0 OK
1 Out of memory
*/
int hp_get_new_block(HP_BLOCK *block, ulong *alloc_length) int hp_get_new_block(HP_BLOCK *block, ulong *alloc_length)
{ {
...@@ -46,6 +63,18 @@ int hp_get_new_block(HP_BLOCK *block, ulong *alloc_length) ...@@ -46,6 +63,18 @@ int hp_get_new_block(HP_BLOCK *block, ulong *alloc_length)
if (block->level_info[i].free_ptrs_in_block) if (block->level_info[i].free_ptrs_in_block)
break; break;
/*
Allocate space for leaf block plus space for upper level blocks up to
first level that has a free slot to put the pointer.
In some cases we actually allocate more then we need:
Consider e.g. a situation where we have one level 1 block and one level 0
block, the level 0 block is full and this function is called. We only
need a leaf block in this case. Nevertheless, we will get here with i=1
and will also allocate sizeof(HP_PTRS) for non-leaf block and will never
use this space.
This doesn't add much overhead - with current values of sizeof(HP_PTRS)
and my_default_record_cache_size we get about 1/128 unused memory.
*/
*alloc_length=sizeof(HP_PTRS)*i+block->records_in_block* block->recbuffer; *alloc_length=sizeof(HP_PTRS)*i+block->records_in_block* block->recbuffer;
if (!(root=(HP_PTRS*) my_malloc(*alloc_length,MYF(0)))) if (!(root=(HP_PTRS*) my_malloc(*alloc_length,MYF(0))))
return 1; return 1;
...@@ -60,21 +89,33 @@ int hp_get_new_block(HP_BLOCK *block, ulong *alloc_length) ...@@ -60,21 +89,33 @@ int hp_get_new_block(HP_BLOCK *block, ulong *alloc_length)
dont_break(); /* Dont allow SIGHUP or SIGINT */ dont_break(); /* Dont allow SIGHUP or SIGINT */
if ((uint) i == block->levels) if ((uint) i == block->levels)
{ {
/* Adding a new level on top of the existing ones. */
block->levels=i+1; block->levels=i+1;
/*
Use first allocated HP_PTRS as a top-level block. Put the current
block tree into the first slot of a new top-level block.
*/
block->level_info[i].free_ptrs_in_block=HP_PTRS_IN_NOD-1; block->level_info[i].free_ptrs_in_block=HP_PTRS_IN_NOD-1;
((HP_PTRS**) root)[0]= block->root; ((HP_PTRS**) root)[0]= block->root;
block->root=block->level_info[i].last_blocks= root++; block->root=block->level_info[i].last_blocks= root++;
} }
/* Occupy the free slot we've found at level i */
block->level_info[i].last_blocks-> block->level_info[i].last_blocks->
blocks[HP_PTRS_IN_NOD - block->level_info[i].free_ptrs_in_block--]= blocks[HP_PTRS_IN_NOD - block->level_info[i].free_ptrs_in_block--]=
(byte*) root; (byte*) root;
/* Add a block subtree with each node having one left-most child */
for (j=i-1 ; j >0 ; j--) for (j=i-1 ; j >0 ; j--)
{ {
block->level_info[j].last_blocks= root++; block->level_info[j].last_blocks= root++;
block->level_info[j].last_blocks->blocks[0]=(byte*) root; block->level_info[j].last_blocks->blocks[0]=(byte*) root;
block->level_info[j].free_ptrs_in_block=HP_PTRS_IN_NOD-1; block->level_info[j].free_ptrs_in_block=HP_PTRS_IN_NOD-1;
} }
/*
root now points to last (block->records_in_block* block->recbuffer)
allocated bytes. Use it as a leaf block.
*/
block->level_info[0].last_blocks= root; block->level_info[0].last_blocks= root;
allow_break(); /* Allow SIGHUP & SIGINT */ allow_break(); /* Allow SIGHUP & SIGINT */
} }
......
...@@ -97,6 +97,7 @@ void hp_clear_keys(HP_SHARE *info) ...@@ -97,6 +97,7 @@ void hp_clear_keys(HP_SHARE *info)
VOID(hp_free_level(block,block->levels,block->root,(byte*) 0)); VOID(hp_free_level(block,block->levels,block->root,(byte*) 0));
block->levels=0; block->levels=0;
block->last_allocated=0; block->last_allocated=0;
keyinfo->hash_buckets= 0;
} }
} }
info->index_length=0; info->index_length=0;
......
...@@ -128,6 +128,7 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef, ...@@ -128,6 +128,7 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
max_records); max_records);
keyinfo->delete_key= hp_delete_key; keyinfo->delete_key= hp_delete_key;
keyinfo->write_key= hp_write_key; keyinfo->write_key= hp_write_key;
keyinfo->hash_buckets= 0;
} }
} }
share->min_records= min_records; share->min_records= min_records;
......
...@@ -97,8 +97,8 @@ int hp_rb_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo, ...@@ -97,8 +97,8 @@ int hp_rb_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
flag Is set if we want's to correct info->current_ptr flag Is set if we want's to correct info->current_ptr
RETURN RETURN
0 ok 0 Ok
# error number other Error code
*/ */
int hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo, int hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
...@@ -151,6 +151,8 @@ int hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo, ...@@ -151,6 +151,8 @@ int hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
pos->ptr_to_rec=empty->ptr_to_rec; pos->ptr_to_rec=empty->ptr_to_rec;
pos->next_key=empty->next_key; pos->next_key=empty->next_key;
} }
else
keyinfo->hash_buckets--;
if (empty == lastpos) /* deleted last hash key */ if (empty == lastpos) /* deleted last hash key */
DBUG_RETURN (0); DBUG_RETURN (0);
...@@ -187,7 +189,11 @@ int hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo, ...@@ -187,7 +189,11 @@ int hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
} }
pos3= pos; /* Link pos->next after lastpos */ pos3= pos; /* Link pos->next after lastpos */
} }
else pos3= 0; /* Different positions merge */ else
{
pos3= 0; /* Different positions merge */
keyinfo->hash_buckets--;
}
empty[0]=lastpos[0]; empty[0]=lastpos[0];
hp_movelink(pos3, empty, pos->next_key); hp_movelink(pos3, empty, pos->next_key);
......
...@@ -196,7 +196,18 @@ byte *hp_search_next(HP_INFO *info, HP_KEYDEF *keyinfo, const byte *key, ...@@ -196,7 +196,18 @@ byte *hp_search_next(HP_INFO *info, HP_KEYDEF *keyinfo, const byte *key,
} }
/* Calculate pos according to keys */ /*
Calculate position number for hash value.
SYNOPSIS
hp_mask()
hashnr Hash value
buffmax Value such that
2^(n-1) < maxlength <= 2^n = buffmax
maxlength
RETURN
Array index, in [0..maxlength)
*/
ulong hp_mask(ulong hashnr, ulong buffmax, ulong maxlength) ulong hp_mask(ulong hashnr, ulong buffmax, ulong maxlength)
{ {
...@@ -205,7 +216,12 @@ ulong hp_mask(ulong hashnr, ulong buffmax, ulong maxlength) ...@@ -205,7 +216,12 @@ ulong hp_mask(ulong hashnr, ulong buffmax, ulong maxlength)
} }
/* Change link from pos to new_link */ /*
Change
next_link -> ... -> X -> pos
to
next_link -> ... -> X -> newlink
*/
void hp_movelink(HASH_INFO *pos, HASH_INFO *next_link, HASH_INFO *newlink) void hp_movelink(HASH_INFO *pos, HASH_INFO *next_link, HASH_INFO *newlink)
{ {
......
...@@ -36,7 +36,6 @@ int heap_write(HP_INFO *info, const byte *record) ...@@ -36,7 +36,6 @@ int heap_write(HP_INFO *info, const byte *record)
byte *pos; byte *pos;
HP_SHARE *share=info->s; HP_SHARE *share=info->s;
DBUG_ENTER("heap_write"); DBUG_ENTER("heap_write");
#ifndef DBUG_OFF #ifndef DBUG_OFF
if (info->mode & O_RDONLY) if (info->mode & O_RDONLY)
{ {
...@@ -160,7 +159,31 @@ static byte *next_free_record_pos(HP_SHARE *info) ...@@ -160,7 +159,31 @@ static byte *next_free_record_pos(HP_SHARE *info)
block_pos*info->block.recbuffer); block_pos*info->block.recbuffer);
} }
/* Write a hash-key to the hash-index */
/*
Write a hash-key to the hash-index
SYNOPSIS
info Heap table info
keyinfo Key info
record Table record to added
recpos Memory buffer where the table record will be stored if added
successfully
NOTE
Hash index uses HP_BLOCK structure as a 'growable array' of HASH_INFO
structs. Array size == number of entries in hash index.
hp_mask(hp_rec_hashnr()) maps hash entries values to hash array positions.
If there are several hash entries with the same hash array position P,
they are connected in a linked list via HASH_INFO::next_key. The first
list element is located at position P, next elements are located at
positions for which there is no record that should be located at that
position. The order of elements in the list is arbitrary.
RETURN
0 - OK
-1 - Out of memory
HA_ERR_FOUND_DUPP_KEY - Duplicate record on unique key. The record was
still added and the caller must call hp_delete_key for it.
*/
int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo,
const byte *record, byte *recpos) const byte *record, byte *recpos)
...@@ -181,18 +204,53 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, ...@@ -181,18 +204,53 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo,
halfbuff= (long) share->blength >> 1; halfbuff= (long) share->blength >> 1;
pos= hp_find_hash(&keyinfo->block,(first_index=share->records-halfbuff)); pos= hp_find_hash(&keyinfo->block,(first_index=share->records-halfbuff));
/*
We're about to add one more hash array position, with hash_mask=#records.
The number of hash positions will change and some entries might need to
be relocated to the newly added position. Those entries are currently
members of the list that starts at #first_index position (this is
guaranteed by properties of hp_mask(hp_rec_hashnr(X)) mapping function)
At #first_index position currently there may be either:
a) An entry with hashnr != first_index. We don't need to move it.
or
b) A list of items with hash_mask=first_index. The list contains entries
of 2 types:
1) entries that should be relocated to the list that starts at new
position we're adding ('uppper' list)
2) entries that should be left in the list starting at #first_index
position ('lower' list)
*/
if (pos != empty) /* If some records */ if (pos != empty) /* If some records */
{ {
do do
{ {
hashnr = hp_rec_hashnr(keyinfo, pos->ptr_to_rec); hashnr = hp_rec_hashnr(keyinfo, pos->ptr_to_rec);
if (flag == 0) /* First loop; Check if ok */ if (flag == 0)
{
/*
First loop, bail out if we're dealing with case a) from above
comment
*/
if (hp_mask(hashnr, share->blength, share->records) != first_index) if (hp_mask(hashnr, share->blength, share->records) != first_index)
break; break;
}
/*
flag & LOWFIND - found a record that should be put into lower position
flag & LOWUSED - lower position occupied by the record
Same for HIGHFIND and HIGHUSED and 'upper' position
gpos - ptr to last element in lower position's list
gpos2 - ptr to last element in upper position's list
ptr_to_rec - ptr to last entry that should go into lower list.
ptr_to_rec2 - same for upper list.
*/
if (!(hashnr & halfbuff)) if (!(hashnr & halfbuff))
{ /* Key will not move */ {
/* Key should be put into 'lower' list */
if (!(flag & LOWFIND)) if (!(flag & LOWFIND))
{ {
/* key is the first element to go into lower position */
if (flag & HIGHFIND) if (flag & HIGHFIND)
{ {
flag=LOWFIND | HIGHFIND; flag=LOWFIND | HIGHFIND;
...@@ -203,16 +261,21 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, ...@@ -203,16 +261,21 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo,
} }
else else
{ {
flag=LOWFIND | LOWUSED; /* key isn't changed */ /*
We can only get here at first iteration: key is at 'lower'
position pos and should be left here.
*/
flag=LOWFIND | LOWUSED;
gpos=pos; gpos=pos;
ptr_to_rec=pos->ptr_to_rec; ptr_to_rec=pos->ptr_to_rec;
} }
} }
else else
{ {
/* Already have another key for lower position */
if (!(flag & LOWUSED)) if (!(flag & LOWUSED))
{ {
/* Change link of previous LOW-key */ /* Change link of previous lower-list key */
gpos->ptr_to_rec=ptr_to_rec; gpos->ptr_to_rec=ptr_to_rec;
gpos->next_key=pos; gpos->next_key=pos;
flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED); flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
...@@ -222,19 +285,21 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, ...@@ -222,19 +285,21 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo,
} }
} }
else else
{ /* key will be moved */ {
/* key will be put into 'higher' list */
if (!(flag & HIGHFIND)) if (!(flag & HIGHFIND))
{ {
flag= (flag & LOWFIND) | HIGHFIND; flag= (flag & LOWFIND) | HIGHFIND;
/* key shall be moved to the last (empty) position */ /* key shall be moved to the last (empty) position */
gpos2 = empty; empty=pos; gpos2= empty;
empty= pos;
ptr_to_rec2=pos->ptr_to_rec; ptr_to_rec2=pos->ptr_to_rec;
} }
else else
{ {
if (!(flag & HIGHUSED)) if (!(flag & HIGHUSED))
{ {
/* Change link of previous hash-key and save */ /* Change link of previous upper-list key and save */
gpos2->ptr_to_rec=ptr_to_rec2; gpos2->ptr_to_rec=ptr_to_rec2;
gpos2->next_key=pos; gpos2->next_key=pos;
flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED); flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
...@@ -246,6 +311,15 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, ...@@ -246,6 +311,15 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo,
} }
while ((pos=pos->next_key)); while ((pos=pos->next_key));
if ((flag & (LOWFIND | HIGHFIND)) == (LOWFIND | HIGHFIND))
{
/*
If both 'higher' and 'lower' list have at least one element, now
there are two hash buckets instead of one.
*/
keyinfo->hash_buckets++;
}
if ((flag & (LOWFIND | LOWUSED)) == LOWFIND) if ((flag & (LOWFIND | LOWUSED)) == LOWFIND)
{ {
gpos->ptr_to_rec=ptr_to_rec; gpos->ptr_to_rec=ptr_to_rec;
...@@ -265,6 +339,7 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, ...@@ -265,6 +339,7 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo,
{ {
pos->ptr_to_rec=recpos; pos->ptr_to_rec=recpos;
pos->next_key=0; pos->next_key=0;
keyinfo->hash_buckets++;
} }
else else
{ {
...@@ -280,6 +355,7 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, ...@@ -280,6 +355,7 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo,
} }
else else
{ {
keyinfo->hash_buckets++;
pos->ptr_to_rec=recpos; pos->ptr_to_rec=recpos;
pos->next_key=0; pos->next_key=0;
hp_movelink(pos, gpos, empty); hp_movelink(pos, gpos, empty);
......
...@@ -63,18 +63,48 @@ typedef struct st_heap_ptrs ...@@ -63,18 +63,48 @@ typedef struct st_heap_ptrs
struct st_level_info struct st_level_info
{ {
uint free_ptrs_in_block,records_under_level; /* Number of unused slots in *last_blocks HP_PTRS block (0 for 0th level) */
HP_PTRS *last_blocks; /* pointers to HP_PTRS or records */ uint free_ptrs_in_block;
/*
Maximum number of records that can be 'contained' inside of each element
of last_blocks array. For level 0 - 1, for level 1 - HP_PTRS_IN_NOD, for
level 2 - HP_PTRS_IN_NOD^2 and so forth.
*/
uint records_under_level;
/*
Ptr to last allocated HP_PTRS (or records buffer for level 0) on this
level.
*/
HP_PTRS *last_blocks;
}; };
typedef struct st_heap_block /* The data is saved in blocks */
/*
Heap table records and hash index entries are stored in HP_BLOCKs.
HP_BLOCK is used as a 'growable array' of fixed-size records. Size of record
is recbuffer bytes.
The internal representation is as follows:
HP_BLOCK is a hierarchical structure of 'blocks'.
A block at level 0 is an array records_in_block records.
A block at higher level is an HP_PTRS structure with pointers to blocks at
lower levels.
At the highest level there is one top block. It is stored in HP_BLOCK::root.
See hp_find_block for a description of how record pointer is obtained from
its index.
See hp_get_new_block
*/
typedef struct st_heap_block
{ {
HP_PTRS *root; HP_PTRS *root; /* Top-level block */
struct st_level_info level_info[HP_MAX_LEVELS+1]; struct st_level_info level_info[HP_MAX_LEVELS+1];
uint levels; uint levels; /* number of used levels */
uint records_in_block; /* Records in a heap-block */ uint records_in_block; /* Records in one heap-block */
uint recbuffer; /* Length of one saved record */ uint recbuffer; /* Length of one saved record */
ulong last_allocated; /* Blocks allocated, used by keys */ ulong last_allocated; /* number of records there is allocated space for */
} HP_BLOCK; } HP_BLOCK;
struct st_heap_info; /* For referense */ struct st_heap_info; /* For referense */
...@@ -87,6 +117,11 @@ typedef struct st_hp_keydef /* Key definition with open */ ...@@ -87,6 +117,11 @@ typedef struct st_hp_keydef /* Key definition with open */
uint8 algorithm; /* HASH / BTREE */ uint8 algorithm; /* HASH / BTREE */
HA_KEYSEG *seg; HA_KEYSEG *seg;
HP_BLOCK block; /* Where keys are saved */ HP_BLOCK block; /* Where keys are saved */
/*
Number of buckets used in hash table. Used only to provide
#records estimates for heap key scans.
*/
ha_rows hash_buckets;
TREE rb_tree; TREE rb_tree;
int (*write_key)(struct st_heap_info *info, struct st_hp_keydef *keyinfo, int (*write_key)(struct st_heap_info *info, struct st_hp_keydef *keyinfo,
const byte *record, byte *recpos); const byte *record, byte *recpos);
...@@ -102,7 +137,7 @@ typedef struct st_heap_share ...@@ -102,7 +137,7 @@ typedef struct st_heap_share
ulong min_records,max_records; /* Params to open */ ulong min_records,max_records; /* Params to open */
ulong data_length,index_length; ulong data_length,index_length;
uint records; /* records */ uint records; /* records */
uint blength; uint blength; /* records rounded up to 2^n */
uint deleted; /* Deleted records in database */ uint deleted; /* Deleted records in database */
uint reclength; /* Length of one record */ uint reclength; /* Length of one record */
uint changed; uint changed;
......
...@@ -164,9 +164,9 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end, ...@@ -164,9 +164,9 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
if (param.trunc) ftbw->flags|=FTB_FLAG_TRUNC; if (param.trunc) ftbw->flags|=FTB_FLAG_TRUNC;
ftbw->weight=weight; ftbw->weight=weight;
ftbw->up=up; ftbw->up=up;
ftbw->docid[0]=ftbw->docid[1]=HA_POS_ERROR; ftbw->docid[0]=ftbw->docid[1]=HA_OFFSET_ERROR;
ftbw->ndepth= (param.yesno<0) + depth; ftbw->ndepth= (param.yesno<0) + depth;
ftbw->key_root=HA_POS_ERROR; ftbw->key_root=HA_OFFSET_ERROR;
memcpy(ftbw->word+1, w.pos, w.len); memcpy(ftbw->word+1, w.pos, w.len);
ftbw->word[0]=w.len; ftbw->word[0]=w.len;
if (param.yesno > 0) up->ythresh++; if (param.yesno > 0) up->ythresh++;
...@@ -181,7 +181,7 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end, ...@@ -181,7 +181,7 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
ftbe->weight=weight; ftbe->weight=weight;
ftbe->up=up; ftbe->up=up;
ftbe->ythresh=ftbe->yweaks=0; ftbe->ythresh=ftbe->yweaks=0;
ftbe->docid[0]=ftbe->docid[1]=HA_POS_ERROR; ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR;
if ((ftbe->quot=param.quot)) ftb->with_scan|=2; if ((ftbe->quot=param.quot)) ftb->with_scan|=2;
if (param.yesno > 0) up->ythresh++; if (param.yesno > 0) up->ythresh++;
_ftb_parse_query(ftb, start, end, ftbe, depth+1); _ftb_parse_query(ftb, start, end, ftbe, depth+1);
...@@ -259,7 +259,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) ...@@ -259,7 +259,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
{ {
if (!ftbw->off || !(ftbw->flags & FTB_FLAG_TRUNC)) if (!ftbw->off || !(ftbw->flags & FTB_FLAG_TRUNC))
{ {
ftbw->docid[0]=HA_POS_ERROR; ftbw->docid[0]=HA_OFFSET_ERROR;
if ((ftbw->flags & FTB_FLAG_YES) && ftbw->up->up==0) if ((ftbw->flags & FTB_FLAG_YES) && ftbw->up->up==0)
{ {
/* /*
...@@ -346,7 +346,7 @@ static void _ftb_init_index_search(FT_INFO *ftb) ...@@ -346,7 +346,7 @@ static void _ftb_init_index_search(FT_INFO *ftb)
ftbe->up->ythresh - ftbe->up->yweaks >1) /* 1 */ ftbe->up->ythresh - ftbe->up->yweaks >1) /* 1 */
{ {
FTB_EXPR *top_ftbe=ftbe->up->up; FTB_EXPR *top_ftbe=ftbe->up->up;
ftbw->docid[0]=HA_POS_ERROR; ftbw->docid[0]=HA_OFFSET_ERROR;
for (ftbe=ftbw->up; ftbe != top_ftbe; ftbe=ftbe->up) for (ftbe=ftbw->up; ftbe != top_ftbe; ftbe=ftbe->up)
if (ftbe->flags & FTB_FLAG_YES) if (ftbe->flags & FTB_FLAG_YES)
ftbe->yweaks++; ftbe->yweaks++;
...@@ -387,7 +387,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, ...@@ -387,7 +387,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query,
ftb->charset= ((keynr==NO_SUCH_KEY) ? ftb->charset= ((keynr==NO_SUCH_KEY) ?
default_charset_info : info->s->keyinfo[keynr].seg->charset); default_charset_info : info->s->keyinfo[keynr].seg->charset);
ftb->with_scan=0; ftb->with_scan=0;
ftb->lastpos=HA_POS_ERROR; ftb->lastpos=HA_OFFSET_ERROR;
bzero(& ftb->no_dupes, sizeof(TREE)); bzero(& ftb->no_dupes, sizeof(TREE));
init_alloc_root(&ftb->mem_root, 1024, 1024); init_alloc_root(&ftb->mem_root, 1024, 1024);
...@@ -410,7 +410,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, ...@@ -410,7 +410,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query,
ftbe->quot=0; ftbe->quot=0;
ftbe->up=0; ftbe->up=0;
ftbe->ythresh=ftbe->yweaks=0; ftbe->ythresh=ftbe->yweaks=0;
ftbe->docid[0]=ftbe->docid[1]=HA_POS_ERROR; ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR;
ftb->root=ftbe; ftb->root=ftbe;
_ftb_parse_query(ftb, &query, query+query_len, ftbe, 0); _ftb_parse_query(ftb, &query, query+query_len, ftbe, 0);
ftb->list=(FTB_WORD **)alloc_root(&ftb->mem_root, ftb->list=(FTB_WORD **)alloc_root(&ftb->mem_root,
...@@ -561,7 +561,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) ...@@ -561,7 +561,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record)
while (ftb->state == INDEX_SEARCH && while (ftb->state == INDEX_SEARCH &&
(curdoc=((FTB_WORD *)queue_top(& ftb->queue))->docid[0]) != (curdoc=((FTB_WORD *)queue_top(& ftb->queue))->docid[0]) !=
HA_POS_ERROR) HA_OFFSET_ERROR)
{ {
while (curdoc == (ftbw=(FTB_WORD *)queue_top(& ftb->queue))->docid[0]) while (curdoc == (ftbw=(FTB_WORD *)queue_top(& ftb->queue))->docid[0])
{ {
...@@ -615,7 +615,7 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) ...@@ -615,7 +615,7 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length)
const byte *end; const byte *end;
my_off_t docid=ftb->info->lastpos; my_off_t docid=ftb->info->lastpos;
if (docid == HA_POS_ERROR) if (docid == HA_OFFSET_ERROR)
return -2.0; return -2.0;
if (!ftb->queue.elements) if (!ftb->queue.elements)
return 0; return 0;
...@@ -627,9 +627,9 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) ...@@ -627,9 +627,9 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length)
for (i=0; i < ftb->queue.elements; i++) for (i=0; i < ftb->queue.elements; i++)
{ {
ftb->list[i]->docid[1]=HA_POS_ERROR; ftb->list[i]->docid[1]=HA_OFFSET_ERROR;
for (x=ftb->list[i]->up; x; x=x->up) for (x=ftb->list[i]->up; x; x=x->up)
x->docid[1]=HA_POS_ERROR; x->docid[1]=HA_OFFSET_ERROR;
} }
} }
......
...@@ -134,3 +134,10 @@ select * from t1 where firstname='john' and firstname like binary 'John'; ...@@ -134,3 +134,10 @@ select * from t1 where firstname='john' and firstname like binary 'John';
firstname lastname firstname lastname
John Doe John Doe
drop table t1; drop table t1;
create table t1 (a binary);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` binary(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
...@@ -487,3 +487,18 @@ prepare stmt1 from @str2; ...@@ -487,3 +487,18 @@ prepare stmt1 from @str2;
execute stmt1 using @ivar; execute stmt1 using @ivar;
? ?
1234 1234
SET TIMESTAMP=10000;
create table t2 (c char(30)) charset=ucs2;
set @v=convert('abc' using ucs2);
reset master;
insert into t2 values (@v);
show binlog events from 79;
Log_name Pos Event_type Server_id Orig_log_pos Info
master-bin.000001 79 User var 1 79 @`v`=_ucs2 0x006100620063 COLLATE ucs2_general_ci
master-bin.000001 119 Query 1 119 use `test`; insert into t2 values (@v)
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
SET @`v`:=_ucs2 0x006100620063 COLLATE ucs2_general_ci;
use test;
SET TIMESTAMP=10000;
insert into t2 values (@v);
drop table t2;
...@@ -382,3 +382,12 @@ s ...@@ -382,3 +382,12 @@ s
pra para para pra para para
para para para para para para
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (h text, FULLTEXT (h));
INSERT INTO t1 VALUES ('Jesses Hasse Ling and his syncopators of Swing');
REPAIR TABLE t1;
Table Op Msg_type Msg_text
test.t1 repair status OK
select count(*) from t1;
count(*)
1
drop table t1;
...@@ -4,7 +4,7 @@ insert into t1 values(1,1),(2,2),(3,3),(4,4); ...@@ -4,7 +4,7 @@ insert into t1 values(1,1),(2,2),(3,3),(4,4);
delete from t1 where a=1 or a=0; delete from t1 where a=1 or a=0;
show keys from t1; show keys from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 0 PRIMARY 1 a NULL NULL NULL NULL HASH t1 0 PRIMARY 1 a NULL 3 NULL NULL HASH
select * from t1; select * from t1;
a b a b
2 2 2 2
...@@ -169,7 +169,7 @@ id select_type table type possible_keys key key_len ref rows Extra ...@@ -169,7 +169,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL btn NULL NULL NULL 11 Using where 1 SIMPLE t1 ALL btn NULL NULL NULL 11 Using where
explain select * from t1 where btn="a" and new_col="a"; explain select * from t1 where btn="a" and new_col="a";
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref btn btn 11 const,const 10 Using where 1 SIMPLE t1 ref btn btn 11 const,const 2 Using where
drop table t1; drop table t1;
CREATE TABLE t1 ( CREATE TABLE t1 (
a int default NULL, a int default NULL,
...@@ -182,7 +182,7 @@ SELECT * FROM t1 WHERE a=NULL; ...@@ -182,7 +182,7 @@ SELECT * FROM t1 WHERE a=NULL;
a b a b
explain SELECT * FROM t1 WHERE a IS NULL; explain SELECT * FROM t1 WHERE a IS NULL;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 5 const 10 Using where 1 SIMPLE t1 ref a a 5 const 1 Using where
SELECT * FROM t1 WHERE a<=>NULL; SELECT * FROM t1 WHERE a<=>NULL;
a b a b
NULL 99 NULL 99
...@@ -204,7 +204,7 @@ key a (a) ...@@ -204,7 +204,7 @@ key a (a)
INSERT INTO t1 VALUES (10), (10), (10); INSERT INTO t1 VALUES (10), (10), (10);
EXPLAIN SELECT * FROM t1 WHERE a=10; EXPLAIN SELECT * FROM t1 WHERE a=10;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 5 const 10 Using where 1 SIMPLE t1 ref a a 5 const 3 Using where
SELECT * FROM t1 WHERE a=10; SELECT * FROM t1 WHERE a=10;
a a
10 10
......
drop table if exists t1; drop table if exists t1,t2;
create table t1 (a int not null,b int not null, primary key using HASH (a)) engine=heap comment="testing heaps" avg_row_length=100 min_rows=1 max_rows=100; create table t1 (a int not null,b int not null, primary key using HASH (a)) engine=heap comment="testing heaps" avg_row_length=100 min_rows=1 max_rows=100;
insert into t1 values(1,1),(2,2),(3,3),(4,4); insert into t1 values(1,1),(2,2),(3,3),(4,4);
delete from t1 where a=1 or a=0; delete from t1 where a=1 or a=0;
show keys from t1; show keys from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 0 PRIMARY 1 a NULL NULL NULL NULL HASH t1 0 PRIMARY 1 a NULL 3 NULL NULL HASH
select * from t1; select * from t1;
a b a b
2 2 2 2
...@@ -169,7 +169,7 @@ id select_type table type possible_keys key key_len ref rows Extra ...@@ -169,7 +169,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL btn NULL NULL NULL 11 Using where 1 SIMPLE t1 ALL btn NULL NULL NULL 11 Using where
explain select * from t1 where btn="a" and new_col="a"; explain select * from t1 where btn="a" and new_col="a";
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref btn btn 11 const,const 10 Using where 1 SIMPLE t1 ref btn btn 11 const,const 2 Using where
drop table t1; drop table t1;
CREATE TABLE t1 ( CREATE TABLE t1 (
a int default NULL, a int default NULL,
...@@ -182,7 +182,7 @@ SELECT * FROM t1 WHERE a=NULL; ...@@ -182,7 +182,7 @@ SELECT * FROM t1 WHERE a=NULL;
a b a b
explain SELECT * FROM t1 WHERE a IS NULL; explain SELECT * FROM t1 WHERE a IS NULL;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 5 const 10 Using where 1 SIMPLE t1 ref a a 5 const 1 Using where
SELECT * FROM t1 WHERE a<=>NULL; SELECT * FROM t1 WHERE a<=>NULL;
a b a b
NULL 99 NULL 99
...@@ -203,3 +203,155 @@ DELETE from t1 where a < 100; ...@@ -203,3 +203,155 @@ DELETE from t1 where a < 100;
SELECT * from t1; SELECT * from t1;
a a
DROP TABLE t1; DROP TABLE t1;
create table t1
(
a char(8) not null,
b char(20) not null,
c int not null,
key (a)
) engine=heap;
insert into t1 values ('aaaa', 'prefill-hash=5',0);
insert into t1 values ('aaab', 'prefill-hash=0',0);
insert into t1 values ('aaac', 'prefill-hash=7',0);
insert into t1 values ('aaad', 'prefill-hash=2',0);
insert into t1 values ('aaae', 'prefill-hash=1',0);
insert into t1 values ('aaaf', 'prefill-hash=4',0);
insert into t1 values ('aaag', 'prefill-hash=3',0);
insert into t1 values ('aaah', 'prefill-hash=6',0);
explain select * from t1 where a='aaaa';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where
explain select * from t1 where a='aaab';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where
explain select * from t1 where a='aaac';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where
explain select * from t1 where a='aaad';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where
insert into t1 select * from t1;
explain select * from t1 where a='aaaa';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where
explain select * from t1 where a='aaab';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where
explain select * from t1 where a='aaac';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where
explain select * from t1 where a='aaad';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where
flush tables;
explain select * from t1 where a='aaaa';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaab';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaac';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaad';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 2 Using where
create table t2 as select * from t1;
delete from t1;
insert into t1 select * from t2;
explain select * from t1 where a='aaaa';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where
explain select * from t1 where a='aaab';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where
explain select * from t1 where a='aaac';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where
explain select * from t1 where a='aaad';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where
drop table t1, t2;
create table t1 (
id int unsigned not null primary key auto_increment,
name varchar(20) not null,
index heap_idx(name),
index btree_idx using btree(name)
) engine=heap;
create table t2 (
id int unsigned not null primary key auto_increment,
name varchar(20) not null,
index btree_idx using btree(name),
index heap_idx(name)
) engine=heap;
insert into t1 (name) values ('Matt'), ('Lilu'), ('Corbin'), ('Carly'),
('Suzy'), ('Hoppy'), ('Burrito'), ('Mimi'), ('Sherry'), ('Ben'), ('Phil'),
('Emily'), ('Mike');
insert into t2 select * from t1;
explain select * from t1 where name='matt';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref heap_idx,btree_idx heap_idx 20 const 1 Using where
explain select * from t2 where name='matt';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 20 const 1 Using where
explain select * from t1 where name='Lilu';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref heap_idx,btree_idx heap_idx 20 const 1 Using where
explain select * from t2 where name='Lilu';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 20 const 1 Using where
explain select * from t1 where name='Phil';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref heap_idx,btree_idx heap_idx 20 const 1 Using where
explain select * from t2 where name='Phil';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 20 const 1 Using where
explain select * from t1 where name='Lilu';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref heap_idx,btree_idx heap_idx 20 const 1 Using where
explain select * from t2 where name='Lilu';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 20 const 1 Using where
insert into t1 (name) select name from t2;
insert into t1 (name) select name from t2;
insert into t1 (name) select name from t2;
insert into t1 (name) select name from t2;
insert into t1 (name) select name from t2;
insert into t1 (name) select name from t2;
flush tables;
select count(*) from t1 where name='Matt';
count(*)
7
explain select * from t1 ignore index (btree_idx) where name='matt';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref heap_idx heap_idx 20 const 7 Using where
show index from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 0 PRIMARY 1 id NULL 91 NULL NULL HASH
t1 1 heap_idx 1 name NULL 13 NULL NULL HASH
t1 1 btree_idx 1 name A NULL NULL NULL BTREE
show index from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 0 PRIMARY 1 id NULL 91 NULL NULL HASH
t1 1 heap_idx 1 name NULL 13 NULL NULL HASH
t1 1 btree_idx 1 name A NULL NULL NULL BTREE
create table t3
(
a varchar(20) not null,
b varchar(20) not null,
key (a,b)
) engine=heap;
insert into t3 select name, name from t1;
show index from t3;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t3 1 a 1 a NULL NULL NULL NULL HASH
t3 1 a 2 b NULL 15 NULL NULL HASH
show index from t3;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t3 1 a 1 a NULL NULL NULL NULL HASH
t3 1 a 2 b NULL 15 NULL NULL HASH
explain select * from t1 ignore key(btree_idx), t3 where t1.name='matt' and t3.a = concat('',t1.name) and t3.b=t1.name;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref heap_idx heap_idx 20 const 7 Using where
1 SIMPLE t3 ref a a 40 func,const 6 Using where
drop table t1, t2, t3;
...@@ -277,3 +277,13 @@ Key_blocks_unused KEY_BLOCKS_UNUSED ...@@ -277,3 +277,13 @@ Key_blocks_unused KEY_BLOCKS_UNUSED
set global keycache2.key_buffer_size=0; set global keycache2.key_buffer_size=0;
set global keycache3.key_buffer_size=100; set global keycache3.key_buffer_size=100;
set global keycache3.key_buffer_size=0; set global keycache3.key_buffer_size=0;
create table t1 (mytext text, FULLTEXT (mytext));
insert t1 values ('aaabbb');
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
set GLOBAL key_cache_block_size=2048;
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
...@@ -543,7 +543,7 @@ Warnings: ...@@ -543,7 +543,7 @@ Warnings:
Note 1031 Table storage engine for 't1' doesn't have this option Note 1031 Table storage engine for 't1' doesn't have this option
show keys from t1; show keys from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 1 a 1 a NULL NULL NULL NULL YES HASH t1 1 a 1 a NULL 1000 NULL NULL YES HASH
drop table t1,t2; drop table t1,t2;
create table t1 ( a tinytext, b char(1), index idx (a(1),b) ); create table t1 ( a tinytext, b char(1), index idx (a(1),b) );
insert into t1 values (null,''), (null,''); insert into t1 values (null,''), (null,'');
......
...@@ -2058,6 +2058,10 @@ t2 1 fld3 1 fld3 A NULL NULL NULL BTREE ...@@ -2058,6 +2058,10 @@ t2 1 fld3 1 fld3 A NULL NULL NULL BTREE
drop table t4, t3, t2, t1; drop table t4, t3, t2, t1;
DO 1; DO 1;
DO benchmark(100,1+1),1,1; DO benchmark(100,1+1),1,1;
do default;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
do foobar;
ERROR 42S22: Unknown column 'foobar' in 'field list'
CREATE TABLE t1 ( CREATE TABLE t1 (
id mediumint(8) unsigned NOT NULL auto_increment, id mediumint(8) unsigned NOT NULL auto_increment,
pseudo varchar(35) NOT NULL default '', pseudo varchar(35) NOT NULL default '',
......
...@@ -195,12 +195,7 @@ INSERT INTO t1 VALUES(@`a b`); ...@@ -195,12 +195,7 @@ INSERT INTO t1 VALUES(@`a b`);
SET @`var1`:=_latin1 0x273B616161 COLLATE latin1_swedish_ci; SET @`var1`:=_latin1 0x273B616161 COLLATE latin1_swedish_ci;
SET TIMESTAMP=10000; SET TIMESTAMP=10000;
insert into t1 values (@var1); insert into t1 values (@var1);
SET TIMESTAMP=10000; drop table t1;
create table t2 (c char(30)) charset=ucs2;
SET @`v`:=_ucs2 0x006100620063 COLLATE ucs2_general_ci;
SET TIMESTAMP=10000;
insert into t2 values (@v);
drop table t1, t2;
set @var= NULL ; set @var= NULL ;
select FIELD( @var,'1it','Hit') as my_column; select FIELD( @var,'1it','Hit') as my_column;
my_column my_column
......
...@@ -80,3 +80,10 @@ select * from t1 where firstname='john' and firstname = binary 'john'; ...@@ -80,3 +80,10 @@ select * from t1 where firstname='john' and firstname = binary 'john';
select * from t1 where firstname='John' and firstname like binary 'john'; select * from t1 where firstname='John' and firstname like binary 'john';
select * from t1 where firstname='john' and firstname like binary 'John'; select * from t1 where firstname='john' and firstname like binary 'John';
drop table t1; drop table t1;
#
# Bug #6552 CHAR column w/o length is legal, BINARY w/o length is not
#
create table t1 (a binary);
show create table t1;
drop table t1;
...@@ -323,3 +323,19 @@ set @str1 = 'select ?'; ...@@ -323,3 +323,19 @@ set @str1 = 'select ?';
set @str2 = convert(@str1 using ucs2); set @str2 = convert(@str1 using ucs2);
prepare stmt1 from @str2; prepare stmt1 from @str2;
execute stmt1 using @ivar; execute stmt1 using @ivar;
#
# Check correct binlogging of UCS2 user variables (BUG#3875)
#
SET TIMESTAMP=10000;
create table t2 (c char(30)) charset=ucs2;
set @v=convert('abc' using ucs2);
reset master;
insert into t2 values (@v);
show binlog events from 79;
# more important than SHOW BINLOG EVENTS, mysqlbinlog (where we
# absolutely need variables names to be quoted and strings to be
# escaped).
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
--exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001
drop table t2;
...@@ -295,3 +295,14 @@ insert into t1 (s) values ('p ...@@ -295,3 +295,14 @@ insert into t1 (s) values ('p
select * from t1 where match(s) against('para' in boolean mode); select * from t1 where match(s) against('para' in boolean mode);
select * from t1 where match(s) against('par*' in boolean mode); select * from t1 where match(s) against('par*' in boolean mode);
DROP TABLE t1; DROP TABLE t1;
#
# icc -ip bug (ip = interprocedural optimization)
# bug#5528
#
CREATE TABLE t1 (h text, FULLTEXT (h));
INSERT INTO t1 VALUES ('Jesses Hasse Ling and his syncopators of Swing');
REPAIR TABLE t1;
select count(*) from t1;
drop table t1;
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# #
--disable_warnings --disable_warnings
drop table if exists t1; drop table if exists t1,t2;
--enable_warnings --enable_warnings
create table t1 (a int not null,b int not null, primary key using HASH (a)) engine=heap comment="testing heaps" avg_row_length=100 min_rows=1 max_rows=100; create table t1 (a int not null,b int not null, primary key using HASH (a)) engine=heap comment="testing heaps" avg_row_length=100 min_rows=1 max_rows=100;
...@@ -141,3 +141,113 @@ INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11); ...@@ -141,3 +141,113 @@ INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11);
DELETE from t1 where a < 100; DELETE from t1 where a < 100;
SELECT * from t1; SELECT * from t1;
DROP TABLE t1; DROP TABLE t1;
#
# Hash index # records estimate test
#
create table t1
(
a char(8) not null,
b char(20) not null,
c int not null,
key (a)
) engine=heap;
insert into t1 values ('aaaa', 'prefill-hash=5',0);
insert into t1 values ('aaab', 'prefill-hash=0',0);
insert into t1 values ('aaac', 'prefill-hash=7',0);
insert into t1 values ('aaad', 'prefill-hash=2',0);
insert into t1 values ('aaae', 'prefill-hash=1',0);
insert into t1 values ('aaaf', 'prefill-hash=4',0);
insert into t1 values ('aaag', 'prefill-hash=3',0);
insert into t1 values ('aaah', 'prefill-hash=6',0);
explain select * from t1 where a='aaaa';
explain select * from t1 where a='aaab';
explain select * from t1 where a='aaac';
explain select * from t1 where a='aaad';
insert into t1 select * from t1;
explain select * from t1 where a='aaaa';
explain select * from t1 where a='aaab';
explain select * from t1 where a='aaac';
explain select * from t1 where a='aaad';
# a known effect: table reload causes statistics to be updated:
flush tables;
explain select * from t1 where a='aaaa';
explain select * from t1 where a='aaab';
explain select * from t1 where a='aaac';
explain select * from t1 where a='aaad';
# Check if delete_all_rows() updates #hash_buckets
create table t2 as select * from t1;
delete from t1;
insert into t1 select * from t2;
explain select * from t1 where a='aaaa';
explain select * from t1 where a='aaab';
explain select * from t1 where a='aaac';
explain select * from t1 where a='aaad';
drop table t1, t2;
# Btree and hash index use costs.
create table t1 (
id int unsigned not null primary key auto_increment,
name varchar(20) not null,
index heap_idx(name),
index btree_idx using btree(name)
) engine=heap;
create table t2 (
id int unsigned not null primary key auto_increment,
name varchar(20) not null,
index btree_idx using btree(name),
index heap_idx(name)
) engine=heap;
insert into t1 (name) values ('Matt'), ('Lilu'), ('Corbin'), ('Carly'),
('Suzy'), ('Hoppy'), ('Burrito'), ('Mimi'), ('Sherry'), ('Ben'), ('Phil'),
('Emily'), ('Mike');
insert into t2 select * from t1;
explain select * from t1 where name='matt';
explain select * from t2 where name='matt';
explain select * from t1 where name='Lilu';
explain select * from t2 where name='Lilu';
explain select * from t1 where name='Phil';
explain select * from t2 where name='Phil';
explain select * from t1 where name='Lilu';
explain select * from t2 where name='Lilu';
insert into t1 (name) select name from t2;
insert into t1 (name) select name from t2;
insert into t1 (name) select name from t2;
insert into t1 (name) select name from t2;
insert into t1 (name) select name from t2;
insert into t1 (name) select name from t2;
flush tables;
select count(*) from t1 where name='Matt';
explain select * from t1 ignore index (btree_idx) where name='matt';
show index from t1;
show index from t1;
create table t3
(
a varchar(20) not null,
b varchar(20) not null,
key (a,b)
) engine=heap;
insert into t3 select name, name from t1;
show index from t3;
show index from t3;
# test rec_per_key use for joins.
explain select * from t1 ignore key(btree_idx), t3 where t1.name='matt' and t3.a = concat('',t1.name) and t3.b=t1.name;
drop table t1, t2, t3;
...@@ -156,3 +156,14 @@ set global keycache2.key_buffer_size=0; ...@@ -156,3 +156,14 @@ set global keycache2.key_buffer_size=0;
# Test to set up a too small size for a key cache (bug #2064) # Test to set up a too small size for a key cache (bug #2064)
set global keycache3.key_buffer_size=100; set global keycache3.key_buffer_size=100;
set global keycache3.key_buffer_size=0; set global keycache3.key_buffer_size=0;
# Test case for buf 6447
create table t1 (mytext text, FULLTEXT (mytext));
insert t1 values ('aaabbb');
check table t1;
set GLOBAL key_cache_block_size=2048;
check table t1;
drop table t1;
...@@ -1757,6 +1757,15 @@ drop table t4, t3, t2, t1; ...@@ -1757,6 +1757,15 @@ drop table t4, t3, t2, t1;
DO 1; DO 1;
DO benchmark(100,1+1),1,1; DO benchmark(100,1+1),1,1;
#
# Bug #6449: do default;
#
--error 1064
do default;
--error 1054
do foobar;
# #
# random in WHERE clause # random in WHERE clause
# #
......
...@@ -109,16 +109,13 @@ SET @`a b`='hello'; ...@@ -109,16 +109,13 @@ SET @`a b`='hello';
INSERT INTO t1 VALUES(@`a b`); INSERT INTO t1 VALUES(@`a b`);
set @var1= "';aaa"; set @var1= "';aaa";
insert into t1 values (@var1); insert into t1 values (@var1);
create table t2 (c char(30)) charset=ucs2;
set @v=convert('abc' using ucs2);
insert into t2 values (@v);
show binlog events from 95; show binlog events from 95;
# more important than SHOW BINLOG EVENTS, mysqlbinlog (where we # more important than SHOW BINLOG EVENTS, mysqlbinlog (where we
# absolutely need variables names to be quoted and strings to be # absolutely need variables names to be quoted and strings to be
# escaped). # escaped).
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
--exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001 --exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001
drop table t1, t2; drop table t1;
# #
......
...@@ -1699,11 +1699,12 @@ byte *key_cache_read(KEY_CACHE *keycache, ...@@ -1699,11 +1699,12 @@ byte *key_cache_read(KEY_CACHE *keycache,
keycache_pthread_mutex_unlock(&keycache->cache_lock); keycache_pthread_mutex_unlock(&keycache->cache_lock);
goto no_key_cache; goto no_key_cache;
} }
read_length= length > keycache->key_cache_block_size ?
keycache->key_cache_block_size : length;
KEYCACHE_DBUG_ASSERT(read_length > 0);
offset= (uint) (filepos & (keycache->key_cache_block_size-1)); offset= (uint) (filepos & (keycache->key_cache_block_size-1));
filepos-= offset; filepos-= offset;
read_length= length;
set_if_smaller(read_length, keycache->key_cache_block_size-offset);
KEYCACHE_DBUG_ASSERT(read_length > 0);
#ifndef THREAD #ifndef THREAD
if (block_length > keycache->key_cache_block_size || offset) if (block_length > keycache->key_cache_block_size || offset)
return_buffer=0; return_buffer=0;
...@@ -1773,7 +1774,7 @@ byte *key_cache_read(KEY_CACHE *keycache, ...@@ -1773,7 +1774,7 @@ byte *key_cache_read(KEY_CACHE *keycache,
return (block->buffer); return (block->buffer);
#endif #endif
buff+= read_length; buff+= read_length;
filepos+= read_length; filepos+= read_length+offset;
} while ((length-= read_length)); } while ((length-= read_length));
DBUG_RETURN(start); DBUG_RETURN(start);
...@@ -1835,12 +1836,12 @@ int key_cache_insert(KEY_CACHE *keycache, ...@@ -1835,12 +1836,12 @@ int key_cache_insert(KEY_CACHE *keycache,
keycache_pthread_mutex_unlock(&keycache->cache_lock); keycache_pthread_mutex_unlock(&keycache->cache_lock);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
read_length= length > keycache->key_cache_block_size ?
keycache->key_cache_block_size : length;
KEYCACHE_DBUG_ASSERT(read_length > 0);
offset= (uint) (filepos & (keycache->key_cache_block_size-1)); offset= (uint) (filepos & (keycache->key_cache_block_size-1));
/* Read data into key cache from buff in key_cache_block_size incr. */ /* Read data into key cache from buff in key_cache_block_size incr. */
filepos-= offset; filepos-= offset;
read_length= length;
set_if_smaller(read_length, keycache->key_cache_block_size-offset);
KEYCACHE_DBUG_ASSERT(read_length > 0);
inc_counter_for_resize_op(keycache); inc_counter_for_resize_op(keycache);
keycache->global_cache_r_requests++; keycache->global_cache_r_requests++;
...@@ -1882,7 +1883,7 @@ int key_cache_insert(KEY_CACHE *keycache, ...@@ -1882,7 +1883,7 @@ int key_cache_insert(KEY_CACHE *keycache,
DBUG_RETURN(1); DBUG_RETURN(1);
buff+= read_length; buff+= read_length;
filepos+= read_length; filepos+= read_length+offset;
} while ((length-= read_length)); } while ((length-= read_length));
} }
...@@ -1959,12 +1960,12 @@ int key_cache_write(KEY_CACHE *keycache, ...@@ -1959,12 +1960,12 @@ int key_cache_write(KEY_CACHE *keycache,
keycache_pthread_mutex_unlock(&keycache->cache_lock); keycache_pthread_mutex_unlock(&keycache->cache_lock);
goto no_key_cache; goto no_key_cache;
} }
read_length= length > keycache->key_cache_block_size ?
keycache->key_cache_block_size : length;
KEYCACHE_DBUG_ASSERT(read_length > 0);
offset= (uint) (filepos & (keycache->key_cache_block_size-1)); offset= (uint) (filepos & (keycache->key_cache_block_size-1));
/* Write data in key_cache_block_size increments */ /* Write data in key_cache_block_size increments */
filepos-= offset; filepos-= offset;
read_length= length;
set_if_smaller(read_length, keycache->key_cache_block_size-offset);
KEYCACHE_DBUG_ASSERT(read_length > 0);
inc_counter_for_resize_op(keycache); inc_counter_for_resize_op(keycache);
keycache->global_cache_w_requests++; keycache->global_cache_w_requests++;
...@@ -2032,7 +2033,7 @@ int key_cache_write(KEY_CACHE *keycache, ...@@ -2032,7 +2033,7 @@ int key_cache_write(KEY_CACHE *keycache,
next_block: next_block:
buff+= read_length; buff+= read_length;
filepos+= read_length; filepos+= read_length+offset;
offset= 0; offset= 0;
} while ((length-= read_length)); } while ((length-= read_length));
......
...@@ -238,7 +238,8 @@ ConfigRetriever::verifyConfig(const struct ndb_mgm_configuration * conf, Uint32 ...@@ -238,7 +238,8 @@ ConfigRetriever::verifyConfig(const struct ndb_mgm_configuration * conf, Uint32
char buf[255]; char buf[255];
ndb_mgm_configuration_iterator * it; ndb_mgm_configuration_iterator * it;
it = ndb_mgm_create_configuration_iterator((struct ndb_mgm_configuration *)conf, CFG_SECTION_NODE); it = ndb_mgm_create_configuration_iterator((struct ndb_mgm_configuration *)conf,
CFG_SECTION_NODE);
if(it == 0){ if(it == 0){
BaseString::snprintf(buf, 255, "Unable to create config iterator"); BaseString::snprintf(buf, 255, "Unable to create config iterator");
...@@ -284,8 +285,14 @@ ConfigRetriever::verifyConfig(const struct ndb_mgm_configuration * conf, Uint32 ...@@ -284,8 +285,14 @@ ConfigRetriever::verifyConfig(const struct ndb_mgm_configuration * conf, Uint32
} }
if(_type != m_node_type){ if(_type != m_node_type){
BaseString::snprintf(buf, 255, "Supplied node type(%d) and config node type(%d) " const char *type_s, *alias_s, *type_s2, *alias_s2;
" don't match", m_node_type, _type); alias_s= ndb_mgm_get_node_type_alias_string((enum ndb_mgm_node_type)m_node_type,
&type_s);
alias_s2= ndb_mgm_get_node_type_alias_string((enum ndb_mgm_node_type)_type,
&type_s2);
BaseString::snprintf(buf, 255, "This node type %s(%s) and config "
"node type %s(%s) don't match for nodeid %d",
alias_s, type_s, alias_s2, type_s2, nodeid);
setError(CR_ERROR, buf); setError(CR_ERROR, buf);
return false; return false;
} }
......
...@@ -193,7 +193,7 @@ int main(int argc, char** argv) ...@@ -193,7 +193,7 @@ int main(int argc, char** argv)
* Read configuration files * * Read configuration files *
****************************/ ****************************/
LocalConfig local_config; LocalConfig local_config;
if(!local_config.init(0,glob.local_config_filename)){ if(!local_config.init(opt_connect_str,glob.local_config_filename)){
local_config.printError(); local_config.printError();
goto error_end; goto error_end;
} }
......
...@@ -30,6 +30,18 @@ ...@@ -30,6 +30,18 @@
const char **ha_heap::bas_ext() const const char **ha_heap::bas_ext() const
{ static const char *ext[1]= { NullS }; return ext; } { static const char *ext[1]= { NullS }; return ext; }
/*
Hash index statistics is updated (copied from HP_KEYDEF::hash_buckets to
rec_per_key) after 1/HEAP_STATS_UPDATE_THRESHOLD fraction of table records
have been inserted/updated/deleted. delete_all_rows() and table flush cause
immediate update.
NOTE
hash index statistics must be updated when number of table records changes
from 0 to non-zero value and vice versa. Otherwise records_in_range may
erroneously return 0 and 'range' may miss records.
*/
#define HEAP_STATS_UPDATE_THRESHOLD 10
int ha_heap::open(const char *name, int mode, uint test_if_locked) int ha_heap::open(const char *name, int mode, uint test_if_locked)
{ {
...@@ -48,6 +60,8 @@ int ha_heap::open(const char *name, int mode, uint test_if_locked) ...@@ -48,6 +60,8 @@ int ha_heap::open(const char *name, int mode, uint test_if_locked)
{ {
/* Initialize variables for the opened table */ /* Initialize variables for the opened table */
set_keys_for_scanning(); set_keys_for_scanning();
if (table->tmp_table == NO_TMP_TABLE)
update_key_stats();
} }
return (file ? 0 : 1); return (file ? 0 : 1);
} }
...@@ -84,28 +98,58 @@ void ha_heap::set_keys_for_scanning(void) ...@@ -84,28 +98,58 @@ void ha_heap::set_keys_for_scanning(void)
} }
} }
void ha_heap::update_key_stats()
{
for (uint i= 0; i < table->keys; i++)
{
KEY *key=table->key_info+i;
if (key->algorithm != HA_KEY_ALG_BTREE)
{
ha_rows hash_buckets= file->s->keydef[i].hash_buckets;
key->rec_per_key[key->key_parts-1]=
hash_buckets ? file->s->records/hash_buckets : 0;
}
}
records_changed= 0;
}
int ha_heap::write_row(byte * buf) int ha_heap::write_row(byte * buf)
{ {
int res;
statistic_increment(table->in_use->status_var.ha_write_count,&LOCK_status); statistic_increment(table->in_use->status_var.ha_write_count,&LOCK_status);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time(); table->timestamp_field->set_time();
if (table->next_number_field && buf == table->record[0]) if (table->next_number_field && buf == table->record[0])
update_auto_increment(); update_auto_increment();
return heap_write(file,buf); res= heap_write(file,buf);
if (!res && table->tmp_table == NO_TMP_TABLE &&
++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records)
update_key_stats();
return res;
} }
int ha_heap::update_row(const byte * old_data, byte * new_data) int ha_heap::update_row(const byte * old_data, byte * new_data)
{ {
statistic_increment(table->in_use->status_var.ha_update_count,&LOCK_status); int res;
statistic_increment(ha_update_count,&LOCK_status);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time(); table->timestamp_field->set_time();
return heap_update(file,old_data,new_data); res= heap_update(file,old_data,new_data);
if (!res && table->tmp_table == NO_TMP_TABLE &&
++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records)
update_key_stats();
return res;
} }
int ha_heap::delete_row(const byte * buf) int ha_heap::delete_row(const byte * buf)
{ {
int res;
statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status); statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status);
return heap_delete(file,buf); res= heap_delete(file,buf);
if (!res && table->tmp_table == NO_TMP_TABLE &&
++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records)
update_key_stats();
return res;
} }
int ha_heap::index_read(byte * buf, const byte * key, uint key_len, int ha_heap::index_read(byte * buf, const byte * key, uint key_len,
...@@ -236,6 +280,8 @@ int ha_heap::extra(enum ha_extra_function operation) ...@@ -236,6 +280,8 @@ int ha_heap::extra(enum ha_extra_function operation)
int ha_heap::delete_all_rows() int ha_heap::delete_all_rows()
{ {
heap_clear(file); heap_clear(file);
if (table->tmp_table == NO_TMP_TABLE)
update_key_stats();
return 0; return 0;
} }
...@@ -393,7 +439,8 @@ ha_rows ha_heap::records_in_range(uint inx, key_range *min_key, ...@@ -393,7 +439,8 @@ ha_rows ha_heap::records_in_range(uint inx, key_range *min_key,
min_key->flag != HA_READ_KEY_EXACT || min_key->flag != HA_READ_KEY_EXACT ||
max_key->flag != HA_READ_AFTER_KEY) max_key->flag != HA_READ_AFTER_KEY)
return HA_POS_ERROR; // Can only use exact keys return HA_POS_ERROR; // Can only use exact keys
return 10; // Good guess else
return key->rec_per_key[key->key_parts-1];
} }
......
...@@ -27,9 +27,10 @@ class ha_heap: public handler ...@@ -27,9 +27,10 @@ class ha_heap: public handler
{ {
HP_INFO *file; HP_INFO *file;
key_map btree_keys; key_map btree_keys;
/* number of records changed since last statistics update */
public: uint records_changed;
ha_heap(TABLE *table): handler(table), file(0) {} public:
ha_heap(TABLE *table): handler(table), file(0), records_changed(0) {}
~ha_heap() {} ~ha_heap() {}
const char *table_type() const { return "HEAP"; } const char *table_type() const { return "HEAP"; }
const char *index_type(uint inx) const char *index_type(uint inx)
...@@ -97,4 +98,6 @@ class ha_heap: public handler ...@@ -97,4 +98,6 @@ class ha_heap: public handler
HEAP_PTR ptr2=*(HEAP_PTR*)ref2; HEAP_PTR ptr2=*(HEAP_PTR*)ref2;
return ptr1 < ptr2? -1 : (ptr1 > ptr2? 1 : 0); return ptr1 < ptr2? -1 : (ptr1 > ptr2? 1 : 0);
} }
private:
void update_key_stats();
}; };
...@@ -1508,17 +1508,14 @@ innobase_close_connection( ...@@ -1508,17 +1508,14 @@ innobase_close_connection(
*****************************************************************************/ *****************************************************************************/
/******************************************************************** /********************************************************************
This function is not relevant since we store the tables and indexes Gives the file extension of an InnoDB single-table tablespace. */
into our own tablespace, not as files, whose extension this function would
give. */
const char** const char**
ha_innobase::bas_ext() const ha_innobase::bas_ext() const
/*========================*/ /*========================*/
/* out: file extension strings, currently not /* out: file extension string */
used */
{ {
static const char* ext[] = {".InnoDB", NullS}; static const char* ext[] = {".ibd", NullS};
return(ext); return(ext);
} }
......
...@@ -269,7 +269,7 @@ Item_func::Item_func(THD *thd, Item_func *item) ...@@ -269,7 +269,7 @@ Item_func::Item_func(THD *thd, Item_func *item)
Sets as a side effect the following class variables: Sets as a side effect the following class variables:
maybe_null Set if any argument may return NULL maybe_null Set if any argument may return NULL
with_sum_func Set if any of the arguments contains a sum function with_sum_func Set if any of the arguments contains a sum function
used_table_cache Set to union of the arguments used table used_tables_cache Set to union of the tables used by arguments
str_value.charset If this is a string function, set this to the str_value.charset If this is a string function, set this to the
character set for the first argument. character set for the first argument.
......
...@@ -1150,7 +1150,7 @@ bool net_request_file(NET* net, const char* fname) ...@@ -1150,7 +1150,7 @@ bool net_request_file(NET* net, const char* fname)
} }
const char *rewrite_db(const char* db, uint *new_len) const char *rewrite_db(const char* db, uint32 *new_len)
{ {
if (replicate_rewrite_db.is_empty() || !db) if (replicate_rewrite_db.is_empty() || !db)
return db; return db;
...@@ -1161,7 +1161,7 @@ const char *rewrite_db(const char* db, uint *new_len) ...@@ -1161,7 +1161,7 @@ const char *rewrite_db(const char* db, uint *new_len)
{ {
if (!strcmp(tmp->key, db)) if (!strcmp(tmp->key, db))
{ {
*new_len= strlen(tmp->val); *new_len= (uint32)strlen(tmp->val);
return tmp->val; return tmp->val;
} }
} }
......
...@@ -508,7 +508,7 @@ int add_table_rule(HASH* h, const char* table_spec); ...@@ -508,7 +508,7 @@ int add_table_rule(HASH* h, const char* table_spec);
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec); int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec);
void init_table_rule_hash(HASH* h, bool* h_inited); void init_table_rule_hash(HASH* h, bool* h_inited);
void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited); void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited);
const char *rewrite_db(const char* db, uint *new_db_len); const char *rewrite_db(const char* db, uint32 *new_db_len);
const char *print_slave_db_safe(const char *db); const char *print_slave_db_safe(const char *db);
int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code); int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code);
void skip_load_data_infile(NET* net); void skip_load_data_infile(NET* net);
......
...@@ -4651,7 +4651,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length) ...@@ -4651,7 +4651,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
- SET uses tot_length. - SET uses tot_length.
*/ */
void calculate_interval_lengths(THD *thd, TYPELIB *interval, void calculate_interval_lengths(THD *thd, TYPELIB *interval,
uint *max_length, uint *tot_length) uint32 *max_length, uint32 *tot_length)
{ {
const char **pos; const char **pos;
uint *len; uint *len;
...@@ -4663,7 +4663,7 @@ void calculate_interval_lengths(THD *thd, TYPELIB *interval, ...@@ -4663,7 +4663,7 @@ void calculate_interval_lengths(THD *thd, TYPELIB *interval,
*len= (uint) strip_sp((char*) *pos); *len= (uint) strip_sp((char*) *pos);
uint length= cs->cset->numchars(cs, *pos, *pos + *len); uint length= cs->cset->numchars(cs, *pos, *pos + *len);
*tot_length+= length; *tot_length+= length;
set_if_bigger(*max_length, length); set_if_bigger(*max_length, (uint32)length);
} }
} }
...@@ -4994,7 +4994,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, ...@@ -4994,7 +4994,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
if (new_field->pack_length > 4) if (new_field->pack_length > 4)
new_field->pack_length=8; new_field->pack_length=8;
new_field->interval=interval; new_field->interval=interval;
uint dummy_max_length; uint32 dummy_max_length;
calculate_interval_lengths(thd, interval, calculate_interval_lengths(thd, interval,
&dummy_max_length, &new_field->length); &dummy_max_length, &new_field->length);
new_field->length+= (interval->count - 1); new_field->length+= (interval->count - 1);
...@@ -5024,7 +5024,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, ...@@ -5024,7 +5024,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
new_field->interval=interval; new_field->interval=interval;
new_field->pack_length=interval->count < 256 ? 1 : 2; // Should be safe new_field->pack_length=interval->count < 256 ? 1 : 2; // Should be safe
uint dummy_tot_length; uint32 dummy_tot_length;
calculate_interval_lengths(thd, interval, calculate_interval_lengths(thd, interval,
&new_field->length, &dummy_tot_length); &new_field->length, &dummy_tot_length);
set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1); set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
......
...@@ -2750,6 +2750,9 @@ type: ...@@ -2750,6 +2750,9 @@ type:
| BINARY '(' NUM ')' { Lex->length=$3.str; | BINARY '(' NUM ')' { Lex->length=$3.str;
Lex->charset=&my_charset_bin; Lex->charset=&my_charset_bin;
$$=FIELD_TYPE_STRING; } $$=FIELD_TYPE_STRING; }
| BINARY { Lex->length= (char*) "1";
Lex->charset=&my_charset_bin;
$$=FIELD_TYPE_STRING; }
| varchar '(' NUM ')' opt_binary { Lex->length=$3.str; | varchar '(' NUM ')' opt_binary { Lex->length=$3.str;
$$=FIELD_TYPE_VAR_STRING; } $$=FIELD_TYPE_VAR_STRING; }
| nvarchar '(' NUM ')' { Lex->length=$3.str; | nvarchar '(' NUM ')' { Lex->length=$3.str;
...@@ -5413,11 +5416,12 @@ do: DO_SYM ...@@ -5413,11 +5416,12 @@ do: DO_SYM
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->sql_command = SQLCOM_DO; lex->sql_command = SQLCOM_DO;
if (!(lex->insert_list = new List_item)) mysql_init_select(lex);
YYABORT; }
expr_list
{
Lex->insert_list= $3;
} }
values
{}
; ;
/* /*
......
...@@ -89,7 +89,12 @@ typedef struct st_key { ...@@ -89,7 +89,12 @@ typedef struct st_key {
enum ha_key_alg algorithm; enum ha_key_alg algorithm;
KEY_PART_INFO *key_part; KEY_PART_INFO *key_part;
char *name; /* Name of key */ char *name; /* Name of key */
ulong *rec_per_key; /* Key part distribution */ /*
Array of AVG(#records with the same field value) for 1st ... Nth key part.
0 means 'not known'.
For temporary heap tables this member is NULL.
*/
ulong *rec_per_key;
union { union {
int bdb_return_if_eq; int bdb_return_if_eq;
} handler; } handler;
......
...@@ -541,7 +541,7 @@ int my_strnncoll_tis620(CHARSET_INFO *cs __attribute__((unused)), ...@@ -541,7 +541,7 @@ int my_strnncoll_tis620(CHARSET_INFO *cs __attribute__((unused)),
tc1= buf; tc1= buf;
if ((len1 + len2 +2) > (int) sizeof(buf)) if ((len1 + len2 +2) > (int) sizeof(buf))
tc1= (uchar*) malloc(len1+len2); tc1= (uchar*) malloc(len1+len2+2);
tc2= tc1 + len1+1; tc2= tc1 + len1+1;
memcpy((char*) tc1, (char*) s1, len1); memcpy((char*) tc1, (char*) s1, len1);
tc1[len1]= 0; /* if length(s1)> len1, need to put 'end of string' */ tc1[len1]= 0; /* if length(s1)> len1, need to put 'end of string' */
...@@ -568,7 +568,7 @@ int my_strnncollsp_tis620(CHARSET_INFO * cs __attribute__((unused)), ...@@ -568,7 +568,7 @@ int my_strnncollsp_tis620(CHARSET_INFO * cs __attribute__((unused)),
a= buf; a= buf;
if ((a_length + b_length +2) > (int) sizeof(buf)) if ((a_length + b_length +2) > (int) sizeof(buf))
alloced= a= (uchar*) malloc(a_length+b_length); alloced= a= (uchar*) malloc(a_length+b_length+2);
b= a + a_length+1; b= a + a_length+1;
memcpy((char*) a, (char*) a0, a_length); memcpy((char*) a, (char*) a0, a_length);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment