summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <serg@serg.mylan>2003-10-15 12:25:44 +0200
committerunknown <serg@serg.mylan>2003-10-15 12:25:44 +0200
commitb192ab5edc45bf221f99ed53ce4d975160d830fa (patch)
tree39df3a873ccd4aba6541c6659c5508843742f8be
parent9456073f90354e82c8b31335bac1d486c88f2f4a (diff)
parentbbfa68d10202df2bf6bc8193d3355fb22f31cff7 (diff)
downloadmariadb-git-b192ab5edc45bf221f99ed53ce4d975160d830fa.tar.gz
merged
BitKeeper/etc/ignore: auto-union myisam/myisamdef.h: Auto merged sql/ha_berkeley.cc: Auto merged sql/ha_innodb.h: Auto merged sql/ha_myisam.cc: Auto merged sql/handler.h: Auto merged sql/item.cc: Auto merged sql/item_func.cc: Auto merged sql/mysql_priv.h: Auto merged sql/mysqld.cc: Auto merged sql/opt_range.cc: Auto merged sql/slave.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_show.cc: Auto merged sql/sql_test.cc: Auto merged sql/table.cc: Auto merged
-rw-r--r--.bzrignore1
-rw-r--r--heap/hp_info.c3
-rw-r--r--include/my_bitmap.h26
-rw-r--r--myisam/ft_boolean_search.c33
-rw-r--r--myisam/ft_parser.c9
-rw-r--r--myisam/ft_update.c59
-rw-r--r--myisam/ftdefs.h5
-rw-r--r--myisam/fulltext.h2
-rw-r--r--myisam/mi_delete.c18
-rw-r--r--myisam/mi_open.c7
-rw-r--r--myisam/mi_write.c85
-rw-r--r--myisam/myisamdef.h6
-rw-r--r--mysql-test/r/fulltext.result3
-rw-r--r--mysql-test/r/fulltext2.result104
-rw-r--r--mysql-test/t/fulltext.test1
-rw-r--r--mysql-test/t/fulltext2.test80
-rw-r--r--mysys/my_bitmap.c188
-rw-r--r--sql/field.cc3
-rw-r--r--sql/field.h4
-rw-r--r--sql/ha_berkeley.cc12
-rw-r--r--sql/ha_berkeley.h2
-rw-r--r--sql/ha_innodb.h2
-rw-r--r--sql/ha_isam.cc2
-rw-r--r--sql/ha_myisam.cc25
-rw-r--r--sql/ha_myisammrg.cc2
-rw-r--r--sql/handler.h2
-rw-r--r--sql/item.cc20
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/item_timefunc.cc6
-rw-r--r--sql/mysql_priv.h117
-rw-r--r--sql/mysqld.cc2
-rw-r--r--sql/opt_range.cc32
-rw-r--r--sql/opt_range.h2
-rw-r--r--sql/opt_sum.cc6
-rw-r--r--sql/slave.cc2
-rw-r--r--sql/sql_acl.cc8
-rw-r--r--sql/sql_base.cc42
-rw-r--r--sql/sql_delete.cc7
-rw-r--r--sql/sql_select.cc208
-rw-r--r--sql/sql_select.h6
-rw-r--r--sql/sql_show.cc2
-rw-r--r--sql/sql_test.cc5
-rw-r--r--sql/sql_update.cc13
-rw-r--r--sql/table.cc24
-rw-r--r--sql/unireg.cc2
45 files changed, 911 insertions, 279 deletions
diff --git a/.bzrignore b/.bzrignore
index 3dc7f26cfbe..339dc8f33ee 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -590,6 +590,7 @@ sql/sql_yacc.cc
sql/sql_yacc.h
sql/sql_yacc.output
sql/sql_yacc.yy.orig
+sql/udf_example.so
sql_error.cc
sql_prepare.cc
stamp-h
diff --git a/heap/hp_info.c b/heap/hp_info.c
index 3122a665fac..e10d140e1f6 100644
--- a/heap/hp_info.c
+++ b/heap/hp_info.c
@@ -44,8 +44,7 @@ ulong heap_position_old(HP_INFO *info)
/* Note that heap_info does NOT return information about the
current position anymore; Use heap_position instead */
-int heap_info(reg1 HP_INFO *info,reg2 HEAPINFO *x,
- int flag __attribute__((unused)))
+int heap_info(reg1 HP_INFO *info,reg2 HEAPINFO *x, int flag )
{
DBUG_ENTER("heap_info");
x->records = info->s->records;
diff --git a/include/my_bitmap.h b/include/my_bitmap.h
index ca0037addfb..d3fcece290b 100644
--- a/include/my_bitmap.h
+++ b/include/my_bitmap.h
@@ -39,15 +39,23 @@ typedef struct st_bitmap
#ifdef __cplusplus
extern "C" {
#endif
- extern my_bool bitmap_init(MY_BITMAP *bitmap, uint bitmap_size,
- my_bool thread_safe);
- extern void bitmap_free(MY_BITMAP *bitmap);
- extern void bitmap_set_bit(MY_BITMAP *bitmap, uint bitmap_bit);
- extern uint bitmap_set_next(MY_BITMAP *bitmap);
- extern void bitmap_set_all(MY_BITMAP* bitmap);
- extern my_bool bitmap_is_set(MY_BITMAP* bitmap, uint bitmap_bit);
- extern void bitmap_clear_all(MY_BITMAP* bitmap);
- extern void bitmap_clear_bit(MY_BITMAP *bitmap, uint bitmap_bit);
+extern my_bool bitmap_cmp(MY_BITMAP *map1, MY_BITMAP *map2);
+extern my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size, my_bool thread_safe);
+extern my_bool bitmap_is_clear_all(MY_BITMAP *map);
+extern my_bool bitmap_is_prefix(MY_BITMAP *map, uint prefix_size);
+extern my_bool bitmap_is_set(MY_BITMAP *map, uint bitmap_bit);
+extern my_bool bitmap_is_set_all(MY_BITMAP *map);
+extern my_bool bitmap_is_subset(MY_BITMAP *map1, MY_BITMAP *map2);
+extern uint bitmap_set_next(MY_BITMAP *map);
+extern void bitmap_clear_all(MY_BITMAP *map);
+extern void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit);
+extern void bitmap_free(MY_BITMAP *map);
+extern void bitmap_intersect(MY_BITMAP *map, MY_BITMAP *map2);
+extern void bitmap_set_all(MY_BITMAP *map);
+extern void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit);
+extern void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size);
+extern void bitmap_subtract(MY_BITMAP *map, MY_BITMAP *map2);
+extern void bitmap_union(MY_BITMAP *map, MY_BITMAP *map2);
#ifdef __cplusplus
}
#endif
diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c
index 2fbd6490cfd..104acf02324 100644
--- a/myisam/ft_boolean_search.c
+++ b/myisam/ft_boolean_search.c
@@ -168,7 +168,11 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
ftbw->word[0]=w.len;
if (param.yesno > 0) up->ythresh++;
queue_insert(& ftb->queue, (byte *)ftbw);
+#ifdef TO_BE_REMOVED
+ /* after removing the following line,
+ ftb->with_scan handling can be simplified (no longer a bitmap) */
ftb->with_scan|=(param.trunc & FTB_FLAG_TRUNC);
+#endif
break;
case 2: /* left bracket */
ftbe=(FTB_EXPR *)alloc_root(&ftb->mem_root, sizeof(FTB_EXPR));
@@ -387,25 +391,34 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query,
}
-/* returns 1 if str0 contain str1 */
+/* returns 1 if str0 ~= /\<str1\>/ */
static int _ftb_strstr(const byte *s0, const byte *e0,
const byte *s1, const byte *e1,
CHARSET_INFO *cs)
{
- const byte *p;
+ const byte *p0, *p1;
+ my_bool s_after, e_before;
- while (s0 < e0)
+ s_after=true_word_char(cs, s1[0]);
+ e_before=true_word_char(cs, e1[-1]);
+ p0=s0;
+
+ while (p0 < e0)
{
- while (s0 < e0 && cs->to_upper[(uint) (uchar) *s0++] !=
+ while (p0 < e0 && cs->to_upper[(uint) (uchar) *p0++] !=
cs->to_upper[(uint) (uchar) *s1])
/* no-op */;
- if (s0 >= e0)
+ if (p0 >= e0)
return 0;
- p=s1+1;
- while (s0 < e0 && p < e1 && cs->to_upper[(uint) (uchar) *s0] ==
- cs->to_upper[(uint) (uchar) *p])
- s0++, p++;
- if (p >= e1)
+
+ if (s_after && p0-1 > s0 && true_word_char(cs, p0[-2]))
+ continue;
+
+ p1=s1+1;
+ while (p0 < e0 && p1 < e1 && cs->to_upper[(uint) (uchar) *p0] ==
+ cs->to_upper[(uint) (uchar) *p1])
+ p0++, p1++;
+ if (p1 == e1 && (!e_before || p0 == e0 || !true_word_char(cs, p0[0])))
return 1;
}
return 0;
diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c
index 14c67333734..57b379cfac0 100644
--- a/myisam/ft_parser.c
+++ b/myisam/ft_parser.c
@@ -73,15 +73,6 @@ FT_WORD * ft_linearize(TREE *wtree)
DBUG_RETURN(wlist);
}
-#define true_word_char(s,X) (my_isalnum(s,X) || (X)=='_')
-#ifdef HYPHEN_IS_DELIM
-#define misc_word_char(X) ((X)=='\'')
-#else
-#define misc_word_char(X) ((X)=='\'' || (X)=='-')
-#endif
-#define word_char(s,X) (true_word_char(s,X) || misc_word_char(X))
-
-
/* returns:
* 0 - eof
* 1 - word found
diff --git a/myisam/ft_update.c b/myisam/ft_update.c
index cdf3b306087..8423b6898cd 100644
--- a/myisam/ft_update.c
+++ b/myisam/ft_update.c
@@ -21,13 +21,6 @@
#include "ftdefs.h"
#include <math.h>
-/**************************************************************
- This is to make ft-code to ignore keyseg.length at all *
- and to index the whole VARCHAR/BLOB instead... */
-#undef set_if_smaller
-#define set_if_smaller(A,B) /* no op */
-/**************************************************************/
-
void _mi_ft_segiterator_init(MI_INFO *info, uint keynr, const byte *record,
FT_SEG_ITERATOR *ftsi)
{
@@ -88,7 +81,6 @@ uint _mi_ft_segiterator(register FT_SEG_ITERATOR *ftsi)
{
ftsi->len=uint2korr(ftsi->pos);
ftsi->pos+=2; /* Skip VARCHAR length */
- set_if_smaller(ftsi->len,ftsi->seg->length);
DBUG_RETURN(1);
}
if (ftsi->seg->flag & HA_BLOB_PART)
@@ -96,7 +88,6 @@ uint _mi_ft_segiterator(register FT_SEG_ITERATOR *ftsi)
ftsi->len=_mi_calc_blob_length(ftsi->seg->bit_start,ftsi->pos);
memcpy_fixed((char*) &ftsi->pos, ftsi->pos+ftsi->seg->bit_start,
sizeof(char*));
- set_if_smaller(ftsi->len,ftsi->seg->length);
DBUG_RETURN(1);
}
ftsi->len=ftsi->seg->length;
@@ -305,3 +296,53 @@ uint _ft_make_key(MI_INFO *info, uint keynr, byte *keybuf, FT_WORD *wptr,
memcpy(buf+HA_FT_WLEN+2,wptr->pos,wptr->len);
DBUG_RETURN(_mi_make_key(info,keynr,(uchar*) keybuf,buf,filepos));
}
+
+/*
+ convert key value to ft2
+*/
+uint _mi_ft_convert_to_ft2(MI_INFO *info, uint keynr, uchar *key)
+{
+ my_off_t root;
+ DYNAMIC_ARRAY *da=info->ft1_to_ft2;
+ MI_KEYDEF *keyinfo=&info->s->ft2_keyinfo;
+ uchar *key_ptr=dynamic_array_ptr(da, 0), *end;
+ uint length, key_length;
+ DBUG_ENTER("_mi_ft_convert_to_ft2");
+
+ /* we'll generate one pageful at once, and insert the rest one-by-one */
+ /* calculating the length of this page ...*/
+ length=(keyinfo->block_length-2) / keyinfo->keylength;
+ set_if_smaller(length, da->elements);
+ length=length * keyinfo->keylength;
+
+ get_key_full_length_rdonly(key_length, key);
+ while (_mi_ck_delete(info, keynr, key, key_length) == 0)
+ /* nothing to do here.
+ _mi_ck_delete() will populate info->ft1_to_ft2 with deleted keys
+ */;
+
+ /* creating pageful of keys */
+ mi_putint(info->buff,length+2,0);
+ memcpy(info->buff+2, key_ptr, length);
+ info->buff_used=info->page_changed=1; /* info->buff is used */
+ if ((root= _mi_new(info,keyinfo)) == HA_OFFSET_ERROR ||
+ _mi_write_keypage(info,keyinfo,root,info->buff))
+ DBUG_RETURN(-1);
+
+ /* inserting the rest of key values */
+ end=dynamic_array_ptr(da, da->elements);
+ for (key_ptr+=length; key_ptr < end; key_ptr+=keyinfo->keylength)
+ if(_mi_ck_real_write_btree(info, keyinfo, key_ptr, 0, &root, SEARCH_SAME))
+ DBUG_RETURN(-1);
+
+ /* now, writing the word key entry */
+ ft_intXstore(key+key_length, -da->elements);
+ _mi_dpointer(info, key+key_length+HA_FT_WLEN, root);
+
+ DBUG_RETURN(_mi_ck_real_write_btree(info,
+ info->s->keyinfo+keynr,
+ key, 0,
+ &info->s->state.key_root[keynr],
+ SEARCH_SAME));
+}
+
diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h
index 88d7e79937b..c0a19262dcf 100644
--- a/myisam/ftdefs.h
+++ b/myisam/ftdefs.h
@@ -22,8 +22,9 @@
#include <m_ctype.h>
#include <my_tree.h>
-#define HYPHEN_IS_DELIM
-#define HYPHEN_IS_CONCAT /* not used for now */
+#define true_word_char(s,X) (my_isalnum(s,X) || (X)=='_')
+#define misc_word_char(X) ((X)=='\'')
+#define word_char(s,X) (true_word_char(s,X) || misc_word_char(X))
#define COMPILE_STOPWORDS_IN
diff --git a/myisam/fulltext.h b/myisam/fulltext.h
index ec267eb3e86..d8c74d4e94b 100644
--- a/myisam/fulltext.h
+++ b/myisam/fulltext.h
@@ -34,3 +34,5 @@ int _mi_ft_cmp(MI_INFO *, uint, const byte *, const byte *);
int _mi_ft_add(MI_INFO *, uint, byte *, const byte *, my_off_t);
int _mi_ft_del(MI_INFO *, uint, byte *, const byte *, my_off_t);
+uint _mi_ft_convert_to_ft2(MI_INFO *, uint, uchar *);
+
diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c
index 2ab5c5d0319..d8e1aef5eb6 100644
--- a/myisam/mi_delete.c
+++ b/myisam/mi_delete.c
@@ -18,6 +18,7 @@
#include "fulltext.h"
#include "rt_index.h"
+#include <assert.h>
#ifdef __WIN__
#include <errno.h>
@@ -231,13 +232,22 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
get_key_full_length_rdonly(off, lastkey);
subkeys=ft_sintXkorr(lastkey+off);
+ DBUG_ASSERT(info->ft1_to_ft2==0 || subkeys >=0);
comp_flag=SEARCH_SAME;
if (subkeys >= 0)
{
/* normal word, one-level tree structure */
- DBUG_PRINT("info",("FT1"));
- flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key,USE_WHOLE_KEY,
- comp_flag, &keypos, lastkey, &last_key);
+ if (info->ft1_to_ft2)
+ {
+ /* we're in ft1->ft2 conversion mode. Saving key data */
+ insert_dynamic(info->ft1_to_ft2, lastkey+off);
+ }
+ else
+ {
+ /* we need exact match only if not in ft1->ft2 conversion mode */
+ flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key,USE_WHOLE_KEY,
+ comp_flag, &keypos, lastkey, &last_key);
+ }
/* fall through to normal delete */
}
else
@@ -252,13 +262,11 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
if (subkeys == -1)
{
/* the last entry in sub-tree */
- DBUG_PRINT("info",("FT2: the last entry"));
_mi_dispose(info, keyinfo, root);
/* fall through to normal delete */
}
else
{
- DBUG_PRINT("info",("FT2: going down"));
keyinfo=&info->s->ft2_keyinfo;
kpos-=keyinfo->keylength+nod_flag; /* we'll modify key entry 'in vivo' */
key+=off;
diff --git a/myisam/mi_open.c b/myisam/mi_open.c
index c4b24acdb77..744bb9bb3b6 100644
--- a/myisam/mi_open.c
+++ b/myisam/mi_open.c
@@ -513,8 +513,8 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
NullS))
goto err;
errpos=6;
-
- if (!have_rtree)
+
+ if (!have_rtree)
info.rtree_recursion_state= NULL;
strmov(info.filename,org_name);
@@ -536,6 +536,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
info.lock_type=F_UNLCK;
info.quick_mode=0;
info.bulk_insert=0;
+ info.ft1_to_ft2=0;
info.errkey= -1;
info.page_changed=1;
pthread_mutex_lock(&share->intern_lock);
@@ -1112,7 +1113,7 @@ char *mi_recinfo_read(char *ptr, MI_COLUMNDEF *recinfo)
/**************************************************************************
Open data file with or without RAID
-We can't use dup() here as the data file descriptors need to have different
+We can't use dup() here as the data file descriptors need to have different
active seek-positions.
The argument file_to_dup is here for the future if there would on some OS
diff --git a/myisam/mi_write.c b/myisam/mi_write.c
index 8e0b7e3530c..b6a7bf50dd0 100644
--- a/myisam/mi_write.c
+++ b/myisam/mi_write.c
@@ -18,6 +18,7 @@
#include "fulltext.h"
#include "rt_index.h"
+#include <assert.h>
#ifdef __WIN__
#include <errno.h>
@@ -124,7 +125,7 @@ int mi_write(MI_INFO *info, byte *record)
else
{
if (share->keyinfo[i].ck_insert(info,i,buff,
- _mi_make_key(info,i,buff,record,filepos)))
+ _mi_make_key(info,i,buff,record,filepos)))
{
if (local_lock_tree)
rw_unlock(&share->key_root_lock[i]);
@@ -264,13 +265,32 @@ int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key,
else
comp_flag=SEARCH_SAME; /* Keys in rec-pos order */
+ error=_mi_ck_real_write_btree(info, keyinfo, key, key_length,
+ root, comp_flag);
+ if (info->ft1_to_ft2)
+ {
+ if (!error)
+ error= _mi_ft_convert_to_ft2(info, keynr, key);
+ delete_dynamic(info->ft1_to_ft2);
+ my_free(info->ft1_to_ft2, MYF(0));
+ info->ft1_to_ft2=0;
+ }
+ DBUG_RETURN(error);
+} /* _mi_ck_write_btree */
+
+int _mi_ck_real_write_btree(MI_INFO *info, MI_KEYDEF *keyinfo,
+ uchar *key, uint key_length, my_off_t *root, uint comp_flag)
+{
+ int error;
+ DBUG_ENTER("_mi_ck_real_write_btree");
+ /* key_length parameter is used only if comp_flag is SEARCH_FIND */
if (*root == HA_OFFSET_ERROR ||
(error=w_search(info, keyinfo, comp_flag, key, key_length,
*root, (uchar *) 0, (uchar*) 0,
(my_off_t) 0, 1)) > 0)
error=_mi_enlarge_root(info,keyinfo,key,root);
DBUG_RETURN(error);
-} /* _mi_ck_write_btree */
+} /* _mi_ck_real_write_btree */
/* Make a new root with key as only pointer */
@@ -359,13 +379,11 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
keyinfo=&info->s->ft2_keyinfo;
key+=off;
keypos-=keyinfo->keylength; /* we'll modify key entry 'in vivo' */
- if ((error=w_search(info, keyinfo, comp_flag, key, HA_FT_WLEN, root,
- (uchar *) 0, (uchar*) 0, (my_off_t) 0, 1)) > 0)
- {
- error=_mi_enlarge_root(info, keyinfo, key, &root);
- _mi_dpointer(info, keypos+HA_FT_WLEN, root);
- }
+ error=_mi_ck_real_write_btree(info, keyinfo, key, 0,
+ &root, comp_flag);
+ _mi_dpointer(info, keypos+HA_FT_WLEN, root);
subkeys--; /* should there be underflow protection ? */
+ DBUG_ASSERT(subkeys < 0);
ft_intXstore(keypos, subkeys);
if (!error)
error=_mi_write_keypage(info,keyinfo,page,temp_buff);
@@ -410,7 +428,6 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo,
uchar *key, uchar *anc_buff, uchar *key_pos, uchar *key_buff,
uchar *father_buff, uchar *father_key_pos, my_off_t father_page,
my_bool insert_last)
-
{
uint a_length,nod_flag;
int t_length;
@@ -464,8 +481,56 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo,
a_length+=t_length;
mi_putint(anc_buff,a_length,nod_flag);
if (a_length <= keyinfo->block_length)
+ {
+ if (keyinfo->block_length - a_length < 32 &&
+ keyinfo->flag & HA_FULLTEXT && key_pos == endpos &&
+ info->s->base.key_reflength <= info->s->base.rec_reflength &&
+ info->s->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD))
+ {
+ /*
+ Normal word. One-level tree. Page is almost full.
+ Let's consider converting.
+ We'll compare 'key' and the first key at anc_buff
+ */
+ uchar *a=key, *b=anc_buff+2+nod_flag;
+ uint alen, blen, ft2len=info->s->ft2_keyinfo.keylength;
+ /* the very first key on the page is always unpacked */
+ DBUG_ASSERT((*b & 128) == 0);
+#if HA_FT_MAXLEN >= 127
+ blen= mi_uint2korr(b); b+=2;
+#else
+ blen= *b++;
+#endif
+ get_key_length(alen,a);
+ DBUG_ASSERT(info->ft1_to_ft2==0);
+ if (alen == blen &&
+ mi_compare_text(keyinfo->seg->charset, a, alen, b, blen, 0)==0)
+ {
+ /* yup. converting */
+ info->ft1_to_ft2=(DYNAMIC_ARRAY *)
+ my_malloc(sizeof(DYNAMIC_ARRAY), MYF(MY_WME));
+ my_init_dynamic_array(info->ft1_to_ft2, ft2len, 300, 50);
+
+ /*
+ now, adding all keys from the page to dynarray
+ if the page is a leaf (if not keys will be deleted later)
+ */
+ if (!nod_flag)
+ {
+ /* let's leave the first key on the page, though, because
+ we cannot easily dispatch an empty page here */
+ b+=blen+ft2len+2;
+ for (a=anc_buff+a_length ; b < a ; b+=ft2len+2)
+ insert_dynamic(info->ft1_to_ft2, b);
+
+ /* fixing the page's length - it contains only one key now */
+ mi_putint(anc_buff,2+blen+ft2len+2,0);
+ }
+ /* the rest will be done when we're back from recursion */
+ }
+ }
DBUG_RETURN(0); /* There is room on page */
-
+ }
/* Page is full */
if (nod_flag)
insert_last=0;
diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h
index 9844bb7b36d..2c5d5eca756 100644
--- a/myisam/myisamdef.h
+++ b/myisam/myisamdef.h
@@ -222,7 +222,8 @@ struct st_myisam_info {
MI_BLOB *blobs; /* Pointer to blobs */
MI_BIT_BUFF bit_buff;
/* accumulate indexfile changes between write's */
- TREE *bulk_insert;
+ TREE *bulk_insert;
+ DYNAMIC_ARRAY *ft1_to_ft2; /* used only in ft1->ft2 conversion */
char *filename; /* parameter to open filename */
uchar *buff, /* Temp area for key */
*lastkey,*lastkey2; /* Last used search key */
@@ -464,6 +465,9 @@ extern int _mi_delete_static_record(MI_INFO *info);
extern int _mi_cmp_static_record(MI_INFO *info,const byte *record);
extern int _mi_read_rnd_static_record(MI_INFO*, byte *,my_off_t, my_bool);
extern int _mi_ck_write(MI_INFO *info,uint keynr,uchar *key,uint length);
+extern int _mi_ck_real_write_btree(MI_INFO *info, MI_KEYDEF *keyinfo,
+ uchar *key, uint key_length,
+ my_off_t *root, uint comp_flag);
extern int _mi_enlarge_root(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key, my_off_t *root);
extern int _mi_insert(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
uchar *anc_buff,uchar *key_pos,uchar *key_buff,
diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result
index e2d35973383..83c77949e2c 100644
--- a/mysql-test/r/fulltext.result
+++ b/mysql-test/r/fulltext.result
@@ -119,7 +119,8 @@ a b
MySQL has now support for full-text search
select * from t1 where MATCH a,b AGAINST ('"text i"' IN BOOLEAN MODE);
a b
-Full-text indexes are called collections
+select * from t1 where MATCH a,b AGAINST ('"xt indexes"' IN BOOLEAN MODE);
+a b
select * from t1 where MATCH a AGAINST ("search" IN BOOLEAN MODE);
a b
Full-text search in MySQL implements vector space model
diff --git a/mysql-test/r/fulltext2.result b/mysql-test/r/fulltext2.result
index a35be210ece..687bc6edfa0 100644
--- a/mysql-test/r/fulltext2.result
+++ b/mysql-test/r/fulltext2.result
@@ -103,4 +103,106 @@ count(*)
select count(*) from t1 where match a against ('aaazzz' in boolean mode);
count(*)
262
-DROP TABLE IF EXISTS t1;
+drop table t1;
+CREATE TABLE t1 (
+i int(10) unsigned not null auto_increment primary key,
+a varchar(255) not null,
+FULLTEXT KEY (a)
+) TYPE=MyISAM;
+select count(*) from t1 where match a against ('aaaxxx');
+count(*)
+260
+select count(*) from t1 where match a against ('aaayyy');
+count(*)
+250
+select count(*) from t1 where match a against ('aaazzz');
+count(*)
+255
+select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
+count(*)
+260
+select count(*) from t1 where match a against ('aaayyy' in boolean mode);
+count(*)
+250
+select count(*) from t1 where match a against ('aaazzz' in boolean mode);
+count(*)
+255
+select count(*) from t1 where match a against ('aaaxxx aaayyy aaazzz');
+count(*)
+765
+select count(*) from t1 where match a against ('aaaxxx aaayyy aaazzz' in boolean mode);
+count(*)
+765
+select count(*) from t1 where match a against ('aaax*' in boolean mode);
+count(*)
+260
+select count(*) from t1 where match a against ('aaay*' in boolean mode);
+count(*)
+250
+select count(*) from t1 where match a against ('aaa*' in boolean mode);
+count(*)
+765
+insert t1 (a) values ('aaaxxx'),('aaayyy');
+insert t1 (a) values ('aaazzz'),('aaazzz'),('aaazzz'),('aaazzz'),('aaazzz');
+select count(*) from t1 where match a against ('aaaxxx');
+count(*)
+261
+select count(*) from t1 where match a against ('aaayyy');
+count(*)
+251
+select count(*) from t1 where match a against ('aaazzz');
+count(*)
+260
+insert t1 (a) values ('aaaxxx 000000');
+select count(*) from t1 where match a against ('000000');
+count(*)
+1
+delete from t1 where match a against ('000000');
+select count(*) from t1 where match a against ('000000');
+count(*)
+0
+select count(*) from t1 where match a against ('aaaxxx');
+count(*)
+261
+delete from t1 where match a against ('aaazzz');
+select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
+count(*)
+261
+select count(*) from t1 where match a against ('aaayyy' in boolean mode);
+count(*)
+251
+select count(*) from t1 where match a against ('aaazzz' in boolean mode);
+count(*)
+0
+select count(*) from t1 where a = 'aaaxxx';
+count(*)
+261
+select count(*) from t1 where a = 'aaayyy';
+count(*)
+251
+select count(*) from t1 where a = 'aaazzz';
+count(*)
+0
+insert t1 (a) values ('aaaxxx 000000');
+select count(*) from t1 where match a against ('000000');
+count(*)
+1
+update t1 set a='aaazzz' where match a against ('000000');
+select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
+count(*)
+261
+select count(*) from t1 where match a against ('aaazzz' in boolean mode);
+count(*)
+1
+update t1 set a='aaazzz' where a = 'aaaxxx';
+update t1 set a='aaaxxx' where a = 'aaayyy';
+select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
+count(*)
+251
+select count(*) from t1 where match a against ('aaayyy' in boolean mode);
+count(*)
+0
+select count(*) from t1 where match a against ('aaazzz' in boolean mode);
+count(*)
+262
+drop table t1;
diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test
index 8c6bb97edf1..5e5d64ced82 100644
--- a/mysql-test/t/fulltext.test
+++ b/mysql-test/t/fulltext.test
@@ -58,6 +58,7 @@ select * from t1 where MATCH a,b AGAINST ('"text search" "now support"' IN BOOL
select * from t1 where MATCH a,b AGAINST ('"text search" -"now support"' IN BOOLEAN MODE);
select * from t1 where MATCH a,b AGAINST ('"text search" +"now support"' IN BOOLEAN MODE);
select * from t1 where MATCH a,b AGAINST ('"text i"' IN BOOLEAN MODE);
+select * from t1 where MATCH a,b AGAINST ('"xt indexes"' IN BOOLEAN MODE);
# boolean w/o index:
diff --git a/mysql-test/t/fulltext2.test b/mysql-test/t/fulltext2.test
index b739d60e3b3..a01ec3a59c9 100644
--- a/mysql-test/t/fulltext2.test
+++ b/mysql-test/t/fulltext2.test
@@ -94,5 +94,83 @@ select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
select count(*) from t1 where match a against ('aaayyy' in boolean mode);
select count(*) from t1 where match a against ('aaazzz' in boolean mode);
-DROP TABLE IF EXISTS t1;
+drop table t1;
+
+CREATE TABLE t1 (
+ i int(10) unsigned not null auto_increment primary key,
+ a varchar(255) not null,
+ FULLTEXT KEY (a)
+) TYPE=MyISAM;
+
+# two-level entry, second-level tree with depth 2
+--disable_query_log
+let $1=260;
+while ($1)
+{
+ eval insert t1 (a) values ('aaaxxx');
+ dec $1;
+}
+let $1=255;
+while ($1)
+{
+ eval insert t1 (a) values ('aaazzz');
+ dec $1;
+}
+let $1=250;
+while ($1)
+{
+ eval insert t1 (a) values ('aaayyy');
+ dec $1;
+}
+--enable_query_log
+
+select count(*) from t1 where match a against ('aaaxxx');
+select count(*) from t1 where match a against ('aaayyy');
+select count(*) from t1 where match a against ('aaazzz');
+select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
+select count(*) from t1 where match a against ('aaayyy' in boolean mode);
+select count(*) from t1 where match a against ('aaazzz' in boolean mode);
+select count(*) from t1 where match a against ('aaaxxx aaayyy aaazzz');
+select count(*) from t1 where match a against ('aaaxxx aaayyy aaazzz' in boolean mode);
+
+select count(*) from t1 where match a against ('aaax*' in boolean mode);
+select count(*) from t1 where match a against ('aaay*' in boolean mode);
+select count(*) from t1 where match a against ('aaa*' in boolean mode);
+
+# mi_write:
+
+insert t1 (a) values ('aaaxxx'),('aaayyy');
+insert t1 (a) values ('aaazzz'),('aaazzz'),('aaazzz'),('aaazzz'),('aaazzz');
+select count(*) from t1 where match a against ('aaaxxx');
+select count(*) from t1 where match a against ('aaayyy');
+select count(*) from t1 where match a against ('aaazzz');
+
+# mi_delete
+insert t1 (a) values ('aaaxxx 000000');
+select count(*) from t1 where match a against ('000000');
+delete from t1 where match a against ('000000');
+select count(*) from t1 where match a against ('000000');
+select count(*) from t1 where match a against ('aaaxxx');
+delete from t1 where match a against ('aaazzz');
+select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
+select count(*) from t1 where match a against ('aaayyy' in boolean mode);
+select count(*) from t1 where match a against ('aaazzz' in boolean mode);
+# double-check without index
+select count(*) from t1 where a = 'aaaxxx';
+select count(*) from t1 where a = 'aaayyy';
+select count(*) from t1 where a = 'aaazzz';
+
+# update
+insert t1 (a) values ('aaaxxx 000000');
+select count(*) from t1 where match a against ('000000');
+update t1 set a='aaazzz' where match a against ('000000');
+select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
+select count(*) from t1 where match a against ('aaazzz' in boolean mode);
+update t1 set a='aaazzz' where a = 'aaaxxx';
+update t1 set a='aaaxxx' where a = 'aaayyy';
+select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
+select count(*) from t1 where match a against ('aaayyy' in boolean mode);
+select count(*) from t1 where match a against ('aaazzz' in boolean mode);
+
+drop table t1;
diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c
index 8834dda98e1..70b15eaa1d8 100644
--- a/mysys/my_bitmap.c
+++ b/mysys/my_bitmap.c
@@ -27,7 +27,7 @@
#include <assert.h>
#include <m_string.h>
-inline void bitmap_lock(MY_BITMAP* map)
+inline void bitmap_lock(MY_BITMAP *map)
{
#ifdef THREAD
if (map->thread_safe)
@@ -35,7 +35,7 @@ inline void bitmap_lock(MY_BITMAP* map)
#endif
}
-inline void bitmap_unlock(MY_BITMAP* map)
+inline void bitmap_unlock(MY_BITMAP *map)
{
#ifdef THREAD
if (map->thread_safe)
@@ -43,9 +43,10 @@ inline void bitmap_unlock(MY_BITMAP* map)
#endif
}
-my_bool bitmap_init(MY_BITMAP *map, uint bitmap_size, my_bool thread_safe)
+my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size, my_bool thread_safe)
{
- if (!(map->bitmap=(uchar*) my_malloc((bitmap_size+7)/8,
+ if (!(map->bitmap=buf) &&
+ !(map->bitmap=(uchar*) my_malloc((bitmap_size+7)/8,
MYF(MY_WME | MY_ZEROFILL))))
return 1;
DBUG_ASSERT(bitmap_size != ~(uint) 0);
@@ -72,6 +73,7 @@ void bitmap_free(MY_BITMAP *map)
void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit)
{
+ DBUG_ASSERT(map->bitmap);
if (bitmap_bit < map->bitmap_size)
{
bitmap_lock(map);
@@ -80,7 +82,6 @@ void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit)
}
}
-
uint bitmap_set_next(MY_BITMAP *map)
{
uchar *bitmap=map->bitmap;
@@ -88,6 +89,7 @@ uint bitmap_set_next(MY_BITMAP *map)
uint bitmap_size=map->bitmap_size;
uint i;
+ DBUG_ASSERT(map->bitmap);
bitmap_lock(map);
for (i=0; i < bitmap_size ; i++, bitmap++)
{
@@ -110,9 +112,9 @@ uint bitmap_set_next(MY_BITMAP *map)
return bit_found;
}
-
void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit)
{
+ DBUG_ASSERT(map->bitmap);
if (bitmap_bit < map->bitmap_size)
{
bitmap_lock(map);
@@ -121,24 +123,184 @@ void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit)
}
}
+void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
+{
+ uint l, m;
+
+ DBUG_ASSERT(map->bitmap);
+ bitmap_lock(map);
+ set_if_smaller(prefix_size, map->bitmap_size);
+ if ((l=prefix_size / 8))
+ memset(map->bitmap, 0xff, l);
+ if ((m=prefix_size & 7))
+ map->bitmap[l++]= (1 << m)-1;
+ if (l < (m=(map->bitmap_size+7)/8))
+ bzero(map->bitmap+l, m-l);
+ bitmap_unlock(map);
+}
+
+void bitmap_clear_all(MY_BITMAP *map)
+{
+ bitmap_set_prefix(map, 0);
+}
+
+void bitmap_set_all(MY_BITMAP *map)
+{
+ bitmap_set_prefix(map, map->bitmap_size);
+}
-void bitmap_set_all(MY_BITMAP* map)
+my_bool bitmap_is_prefix(MY_BITMAP *map, uint prefix_size)
{
+ uint l=prefix_size/8, m=prefix_size & 7, i, res=0;
+
+ DBUG_ASSERT(map->bitmap);
+ if (prefix_size > map->bitmap_size)
+ return 0;
+
bitmap_lock(map);
- memset(map->bitmap, 0xff, (map->bitmap_size+7)/8);
+ for (i=0; i < l; i++)
+ if (map->bitmap[i] != 0xff)
+ goto ret;
+
+ if (m && map->bitmap[i++] != (1 << m)-1)
+ goto ret;
+
+ for (m=(map->bitmap_size+7)/8; i < m; i++)
+ if (map->bitmap[i] != 0)
+ goto ret;
+
+ res=1;
+ret:
bitmap_unlock(map);
+ return res;
+}
+
+my_bool bitmap_is_clear_all(MY_BITMAP *map)
+{
+ return bitmap_is_prefix(map, 0);
+}
+
+my_bool bitmap_is_set_all(MY_BITMAP *map)
+{
+ return bitmap_is_prefix(map, map->bitmap_size);
}
-my_bool bitmap_is_set(MY_BITMAP* map, uint bitmap_bit)
+my_bool bitmap_is_set(MY_BITMAP *map, uint bitmap_bit)
{
+ DBUG_ASSERT(map->bitmap);
return (bitmap_bit < map->bitmap_size) ?
- (map->bitmap[bitmap_bit / 8] & (1 << (bitmap_bit & 7))) :
- 0;
+ (map->bitmap[bitmap_bit / 8] & (1 << (bitmap_bit & 7))) : 0;
+}
+
+my_bool bitmap_is_subset(MY_BITMAP *map1, MY_BITMAP *map2)
+{
+ uint l1, l2, i, res=0;
+ uchar *m1=map1->bitmap, *m2=map2->bitmap;
+
+ DBUG_ASSERT(map1->bitmap);
+ DBUG_ASSERT(map2->bitmap);
+ bitmap_lock(map1);
+ bitmap_lock(map2);
+
+ l1=(map1->bitmap_size+7)/8;
+ l2=(map2->bitmap_size+7)/8;
+ set_if_smaller(l2, l1);
+
+ for (i=0; i < l2; i++)
+ if ((*m1++) & ~(*m2++))
+ goto ret;
+
+ for (; i < l1; i++)
+ if (*m1++)
+ goto ret;
+
+ res=1;
+ret:
+ bitmap_unlock(map2);
+ bitmap_unlock(map1);
+ return res;
+}
+
+my_bool bitmap_cmp(MY_BITMAP *map1, MY_BITMAP *map2)
+{
+ uint res;
+
+ DBUG_ASSERT(map1->bitmap);
+ DBUG_ASSERT(map2->bitmap);
+ bitmap_lock(map1);
+ bitmap_lock(map2);
+
+ res= map1->bitmap_size == map2->bitmap_size &&
+ memcmp(map1->bitmap, map2->bitmap, (map1->bitmap_size+7)/8)==0;
+
+ bitmap_unlock(map2);
+ bitmap_unlock(map1);
+ return res;
}
-void bitmap_clear_all(MY_BITMAP* map)
+void bitmap_intersect(MY_BITMAP *map, MY_BITMAP *map2)
{
+ uint l1, l2, i;
+ uchar *m=map->bitmap, *m2=map2->bitmap;
+
+ DBUG_ASSERT(map->bitmap);
+ DBUG_ASSERT(map2->bitmap);
bitmap_lock(map);
- bzero(map->bitmap,(map->bitmap_size+7)/8);
+ bitmap_lock(map2);
+
+ l1=(map->bitmap_size+7)/8;
+ l2=(map2->bitmap_size+7)/8;
+ set_if_smaller(l2, l1);
+
+ for (i=0; i < l2; i++)
+ *m++ &= *m2++;
+
+ if (l1 > l2)
+ bzero(m, l1-l2);
+
+ bitmap_unlock(map2);
bitmap_unlock(map);
}
+
+void bitmap_subtract(MY_BITMAP *map, MY_BITMAP *map2)
+{
+ uint l1, l2, i;
+ uchar *m=map->bitmap, *m2=map2->bitmap;
+
+ DBUG_ASSERT(map->bitmap);
+ DBUG_ASSERT(map2->bitmap);
+ bitmap_lock(map);
+ bitmap_lock(map2);
+
+ l1=(map->bitmap_size+7)/8;
+ l2=(map2->bitmap_size+7)/8;
+ set_if_smaller(l2, l1);
+
+ for (i=0; i < l2; i++)
+ *m++ &= ~(*m2++);
+
+ bitmap_unlock(map2);
+ bitmap_unlock(map);
+}
+
+void bitmap_union(MY_BITMAP *map, MY_BITMAP *map2)
+{
+ uint l1, l2, i;
+ uchar *m=map->bitmap, *m2=map2->bitmap;
+
+ DBUG_ASSERT(map->bitmap);
+ DBUG_ASSERT(map2->bitmap);
+ bitmap_lock(map);
+ bitmap_lock(map2);
+
+ l1=(map->bitmap_size+7)/8;
+ l2=(map2->bitmap_size+7)/8;
+ set_if_smaller(l2, l1);
+
+ for (i=0; i < l2; i++)
+ *m++ |= *m2++;
+
+ bitmap_unlock(map2);
+ bitmap_unlock(map);
+}
+
diff --git a/sql/field.cc b/sql/field.cc
index 68c9922e887..bb651835194 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -181,8 +181,7 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
:ptr(ptr_arg),null_ptr(null_ptr_arg),
table(table_arg),table_name(table_arg ? table_arg->table_name : 0),
field_name(field_name_arg),
- query_id(0),key_start(0),part_of_key(0),part_of_sortkey(0),
- unireg_check(unireg_check_arg),
+ query_id(0),unireg_check(unireg_check_arg),
field_length(length_arg),null_bit(null_bit_arg),abs_offset(0)
{
flags=null_ptr ? 0: NOT_NULL_FLAG;
diff --git a/sql/field.h b/sql/field.h
index fe5141e9d80..eb0af881121 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -151,7 +151,9 @@ public:
if (tmp->table->maybe_null)
tmp->flags&= ~NOT_NULL_FLAG;
tmp->table= new_table;
- tmp->key_start= tmp->part_of_key= tmp->part_of_sortkey= 0;
+ tmp->key_start.init().clear_all();
+ tmp->part_of_key.init().clear_all();
+ tmp->part_of_sortkey.init().clear_all();
tmp->unireg_check=Field::NONE;
tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG |
ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG);
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 1b99efeaa43..b2e1ef2fe61 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -843,7 +843,7 @@ int ha_berkeley::write_row(byte * record)
ulong thd_options = table->in_use ? table->in_use->options : 0;
for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
{
- key_map changed_keys = 0;
+ key_map changed_keys;
if (using_ignore && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS))
{
if ((error=txn_begin(db_env, transaction, &sub_trans, 0))) /* purecov: deadcode */
@@ -854,7 +854,7 @@ int ha_berkeley::write_row(byte * record)
key_buff, record),
&row, key_type[primary_key])))
{
- changed_keys |= (key_map) 1 << primary_key;
+ changed_keys.set_bit(primary_key);
for (uint keynr=0 ; keynr < table->keys ; keynr++)
{
if (keynr == primary_key)
@@ -867,7 +867,7 @@ int ha_berkeley::write_row(byte * record)
last_dup_key=keynr;
break;
}
- changed_keys |= (key_map) 1 << keynr;
+ changed_keys.set_bit(keynr);
}
}
else
@@ -1089,7 +1089,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
sub_trans = transaction;
for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
{
- key_map changed_keys = 0;
+ key_map changed_keys;
if (using_ignore && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS))
{
if ((error=txn_begin(db_env, transaction, &sub_trans, 0))) /* purecov: deadcode */
@@ -1122,7 +1122,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
}
DBUG_RETURN(error); // Fatal error /* purecov: inspected */
}
- changed_keys |= (key_map)1 << keynr;
+ changed_keys.set_bit(keynr);
if ((error=key_file[keynr]->put(key_file[keynr], sub_trans,
create_key(&key, keynr, key_buff2,
new_row),
@@ -1260,7 +1260,7 @@ int ha_berkeley::delete_row(const byte * record)
DBUG_RETURN((error)); /* purecov: inspected */
create_key(&prim_key, primary_key, key_buff, record);
if (hidden_primary_key)
- keys|= (key_map) 1 << primary_key;
+ keys.set_bit(primary_key);
/* Subtransactions may be used in order to retry the delete in
case we get a DB_LOCK_DEADLOCK error. */
diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h
index f1669e9b6c7..471145c96bf 100644
--- a/sql/ha_berkeley.h
+++ b/sql/ha_berkeley.h
@@ -107,7 +107,7 @@ class ha_berkeley: public handler
uint extra_rec_buf_length() { return BDB_HIDDEN_PRIMARY_KEY_LENGTH; }
ha_rows estimate_number_of_rows();
bool fast_key_read() { return 1;}
- key_map keys_to_use_for_scanning() { return ~(key_map) 0; }
+ const key_map keys_to_use_for_scanning() { return key_map(~0); }
bool has_transactions() { return 1;}
int open(const char *name, int mode, uint test_if_locked);
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 0c89a9d29ce..9ef47a105d6 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -125,7 +125,7 @@ class ha_innobase: public handler
uint max_key_length() const { return((MAX_KEY_LENGTH <= 3500) ?
MAX_KEY_LENGTH : 3500);}
bool fast_key_read() { return 1;}
- key_map keys_to_use_for_scanning() { return ~(key_map) 0; }
+ const key_map& keys_to_use_for_scanning() { return key_map_full; }
bool has_transactions() { return 1;}
int open(const char *name, int mode, uint test_if_locked);
diff --git a/sql/ha_isam.cc b/sql/ha_isam.cc
index 3acc385d251..8025e5169c8 100644
--- a/sql/ha_isam.cc
+++ b/sql/ha_isam.cc
@@ -202,7 +202,7 @@ void ha_isam::info(uint flag)
sortkey = info.sortkey;
block_size=nisam_block_size;
table->keys = min(table->keys,info.keys);
- table->keys_in_use= set_bits(key_map,table->keys);
+ table->keys_in_use.set_prefix(table->keys);
table->db_options_in_use= info.options;
table->db_record_offset=
(table->db_options_in_use &
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 864ee55a85f..ea356a4f17c 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -705,20 +705,21 @@ int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt)
DBUG_ENTER("ha_myisam::preload_keys");
- /* Check validity of the index references */
+ /* Check validity of the index references */
if (table_list->use_index)
{
- key_map kmap= get_key_map_from_key_list(table, table_list->use_index);
- if (kmap == ~(key_map) 0)
+ key_map kmap;
+ get_key_map_from_key_list(&kmap, table, table_list->use_index);
+ if (kmap.is_set_all())
{
errmsg= thd->net.last_error;
error= HA_ADMIN_FAILED;
goto err;
}
- if (kmap)
- map= kmap;
+ if (!kmap.is_clear_all())
+ map= kmap.to_ulonglong();
}
-
+
mi_extra(file, HA_EXTRA_PRELOAD_BUFFER_SIZE,
(void *) &thd->variables.preload_buff_size);
@@ -731,16 +732,16 @@ int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt)
case HA_ERR_OUT_OF_MEM:
errmsg= "Failed to allocate buffer";
break;
- default:
+ default:
char buf[ERRMSGSIZE+20];
- my_snprintf(buf, ERRMSGSIZE,
+ my_snprintf(buf, ERRMSGSIZE,
"Failed to read from index file (errno: %d)", my_errno);
errmsg= buf;
}
error= HA_ADMIN_FAILED;
goto err;
}
-
+
DBUG_RETURN(HA_ADMIN_OK);
err:
@@ -1022,9 +1023,9 @@ void ha_myisam::info(uint flag)
ref_length=info.reflength;
table->db_options_in_use = info.options;
block_size=myisam_block_size;
- table->keys_in_use= (set_bits(key_map, table->keys) &
- (key_map) info.key_map);
- table->keys_for_keyread= table->keys_in_use & ~table->read_only_keys;
+ table->keys_in_use.set_prefix(table->keys).intersect(info.key_map);
+ table->keys_for_keyread= table->keys_in_use;
+ table->keys_for_keyread.subtract(table->read_only_keys);
table->db_record_offset=info.record_offset;
if (table->key_parts)
memcpy((char*) table->key_info[0].rec_per_key,
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index a0449e83222..42c2ba10808 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -228,7 +228,7 @@ void ha_myisammrg::info(uint flag)
#endif
data_file_length=info.data_file_length;
errkey = info.errkey;
- table->keys_in_use= set_bits(key_map, table->keys);
+ table->keys_in_use.set_prefix(table->keys);
table->db_options_in_use = info.options;
table->is_view=1;
mean_rec_length=info.reclength;
diff --git a/sql/handler.h b/sql/handler.h
index b756d9a09fb..5fc63cf30f5 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -241,7 +241,7 @@ public:
virtual double read_time(uint index, uint ranges, ha_rows rows)
{ return rows2double(ranges+rows); }
virtual bool fast_key_read() { return 0;}
- virtual key_map keys_to_use_for_scanning() { return 0; }
+ virtual const key_map& keys_to_use_for_scanning() { return key_map_empty; }
virtual bool has_transactions(){ return 0;}
virtual uint extra_rec_buf_length() { return 0; }
virtual ha_rows estimate_number_of_rows() { return records+EXTRA_RECORDS; }
diff --git a/sql/item.cc b/sql/item.cc
index 4de4951cb51..69082fab4c2 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -799,11 +799,11 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
not_found_field)
{
/*
- We can't find table field in table list of current select,
+ We can't find table field in table list of current select,
consequently we have to find it in outer subselect(s).
- We can't join lists of outer & current select, because of scope
- of view rules. For example if both tables (outer & current) have
- field 'field' it is not mistake to refer to this field without
+ We can't join lists of outer & current select, because of scope
+ of view rules. For example if both tables (outer & current) have
+ field 'field' it is not mistake to refer to this field without
mention of table name, but if we join tables in one list it will
cause error ER_NON_UNIQ_ERROR in find_field_in_tables.
*/
@@ -832,8 +832,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
0)) != not_found_field)
break;
if (sl->resolve_mode == SELECT_LEX::SELECT_MODE &&
- (refer= find_item_in_list(this, sl->item_list, &counter,
- REPORT_EXCEPT_NOT_FOUND)) !=
+ (refer= find_item_in_list(this, sl->item_list, &counter,
+ REPORT_EXCEPT_NOT_FOUND)) !=
(Item **) not_found_item)
break;
if (sl->master_unit()->first_select()->linkage ==
@@ -897,7 +897,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
TABLE *table=field->table;
field->query_id=thd->query_id;
table->used_fields++;
- table->used_keys&=field->part_of_key;
+ table->used_keys.intersect(field->part_of_key);
}
fixed= 1;
return 0;
@@ -906,14 +906,14 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
void Item::init_make_field(Send_field *tmp_field,
enum enum_field_types field_type)
-{
+{
char *empty_name= (char*) "";
- tmp_field->db_name= empty_name;
+ tmp_field->db_name= empty_name;
tmp_field->org_table_name= empty_name;
tmp_field->org_col_name= empty_name;
tmp_field->table_name= empty_name;
tmp_field->col_name= name;
- tmp_field->charsetnr= collation.collation->number;
+ tmp_field->charsetnr= collation.collation->number;
tmp_field->flags=maybe_null ? 0 : NOT_NULL_FLAG;
tmp_field->type=field_type;
tmp_field->length=max_length;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index bc7c95d8929..af9fa692f8b 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2650,7 +2650,7 @@ bool Item_func_match::fix_index()
for (keynr=0 ; keynr < table->keys ; keynr++)
{
if ((table->key_info[keynr].flags & HA_FULLTEXT) &&
- (table->keys_in_use_for_query & (((key_map)1) << keynr)))
+ (table->keys_in_use_for_query.is_set(keynr)))
{
ft_to_key[fts]=keynr;
ft_cnt[fts]=0;
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 31ce2ad9cdc..9a36f8a60a6 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -57,13 +57,13 @@ static String day_names[] =
String("Sunday", &my_charset_latin1)
};
-enum date_time_format_types
-{
+enum date_time_format_types
+{
TIME_ONLY= 0, TIME_MICROSECOND,
DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND
};
-typedef struct date_time_format
+struct date_time_format
{
const char* format_str;
uint length;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a1919bf1a0e..05cb026ad66 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -30,9 +30,114 @@
#undef write /* remove pthread.h macro definition for EMX */
#endif
-typedef ulonglong table_map; /* Used for table bits in join */
-typedef ulong key_map; /* Used for finding keys */
-typedef ulong key_part_map; /* Used for finding key parts */
+template <uint default_width> class Bitmap
+{
+ MY_BITMAP map;
+ uchar buffer[(default_width+7)/8];
+public:
+ Bitmap(uint prefix_to_set=0) { init(); set_prefix(prefix_to_set); }
+ Bitmap& init()
+ {
+ bitmap_init(&map, buffer, default_width, 0);
+ return *this;
+ }
+ uint length() const { return default_width; }
+ Bitmap& operator=(const Bitmap& map2)
+ {
+ init();
+ memcpy(buffer, map2.buffer, sizeof(buffer));
+ return *this;
+ }
+ Bitmap& set_bit(uint n) { bitmap_set_bit(&map, n); return *this; }
+ Bitmap& clear_bit(uint n) { bitmap_clear_bit(&map, n); return *this; }
+ Bitmap& set_prefix(uint n) { bitmap_set_prefix(&map, n); return *this; }
+ Bitmap& set_all() { bitmap_set_all(&map); return *this;}
+ Bitmap& clear_all() { bitmap_clear_all(&map); return *this; }
+ Bitmap& intersect(Bitmap& map2) { bitmap_intersect(&map, &map2.map); return *this; }
+ Bitmap& intersect(ulonglong map2buff)
+ {
+ MY_BITMAP map2;
+ bitmap_init(&map2, (uchar *)&map2buff, sizeof(ulonglong)*8, 0);
+ bitmap_intersect(&map, &map2);
+ return *this;
+ }
+ Bitmap& subtract(Bitmap& map2) { bitmap_subtract(&map, &map2.map); return *this; }
+ Bitmap& merge(Bitmap& map2) { bitmap_union(&map, &map2.map); return *this; }
+ my_bool is_set(uint n) const { return bitmap_is_set((MY_BITMAP*)&map, n); }
+ my_bool is_prefix(uint n) const { return bitmap_is_prefix((MY_BITMAP*)&map, n); }
+ my_bool is_clear_all() const { return bitmap_is_clear_all((MY_BITMAP*)&map); }
+ my_bool is_set_all() const { return bitmap_is_set_all((MY_BITMAP*)&map); }
+ my_bool is_subset(const Bitmap& map2) const { return bitmap_is_subset((MY_BITMAP*)&map, (MY_BITMAP*)&map2.map); }
+ my_bool operator==(const Bitmap& map2) const { return bitmap_cmp((MY_BITMAP*)&map, (MY_BITMAP*)&map2.map); }
+ char *print(char *buf) const
+ {
+ char *s=buf; int i;
+ for (i=sizeof(buffer)-1; i>=0 ; i--)
+ {
+ if ((*s=_dig_vec[buffer[i] >> 4]) != '0')
+ break;
+ if ((*s=_dig_vec[buffer[i] & 15]) != '0')
+ break;
+ }
+ for (s++, i-- ; i>=0 ; i--)
+ {
+ *s++=_dig_vec[buffer[i] >> 4];
+ *s++=_dig_vec[buffer[i] & 15];
+ }
+ *s=0;
+ return buf;
+ }
+ ulonglong to_ulonglong() const
+ {
+ if (sizeof(buffer) >= sizeof(ulonglong))
+ return *(ulonglong*)buffer;
+ ulonglong x=0;
+ memcpy(&x, buffer, sizeof(buffer));
+ return x;
+ }
+};
+
+template <> class Bitmap<64>
+{
+ longlong map;
+public:
+ Bitmap(uint prefix_to_set=0) { set_prefix(prefix_to_set); }
+ Bitmap<64>& init() { return *this; }
+ uint length() const { return 64; }
+ Bitmap<64>& set_bit(uint n) { map|= ((ulonglong)1) << n; return *this; }
+ Bitmap<64>& clear_bit(uint n) { map&= ~(((ulonglong)1) << n); return *this; }
+ Bitmap<64>& set_prefix(uint n)
+ {
+ if (n >= length())
+ set_all();
+ else
+ map= (((ulonglong)1) << n)-1;
+ return *this;
+ }
+ Bitmap<64>& set_all() { map=~(ulonglong)0; return *this;}
+ Bitmap<64>& clear_all() { map=(ulonglong)0; return *this; }
+ Bitmap<64>& intersect(Bitmap<64>& map2) { map&= map2.map; return *this; }
+ Bitmap<64>& intersect(ulonglong map2) { map&= map2; return *this; }
+ Bitmap<64>& subtract(Bitmap<64>& map2) { map&= ~map2.map; return *this; }
+ Bitmap<64>& merge(Bitmap<64>& map2) { map|= map2.map; return *this; }
+ my_bool is_set(uint n) const { return test(map & (((ulonglong)1) << n)); }
+ my_bool is_prefix(uint n) const { return map == (((ulonglong)1) << n)-1; }
+ my_bool is_clear_all() const { return map == (ulonglong)0; }
+ my_bool is_set_all() const { return map == ~(ulonglong)0; }
+ my_bool is_subset(const Bitmap<64>& map2) const { return !(map & ~map2.map); }
+ my_bool operator==(const Bitmap<64>& map2) const { return map == map2.map; }
+ char *print(char *buf) const { longlong2str(map,buf,16); return buf; }
+ ulonglong to_ulonglong() const { return map; }
+};
+
+/* TODO convert all these three maps to Bitmap classes */
+typedef ulonglong table_map; /* Used for table bits in join */
+typedef Bitmap<64> key_map; /* Used for finding keys */
+typedef ulong key_part_map; /* Used for finding key parts */
+
+/* useful constants */
+extern const key_map key_map_empty;
+extern const key_map key_map_full;
#include "mysql_com.h"
#include <violite.h>
@@ -634,8 +739,8 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
extern const Item **not_found_item;
Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
find_item_error_report_type report_error);
-key_map get_key_map_from_key_list(TABLE *table,
- List<String> *index_list);
+void get_key_map_from_key_list(key_map *map, TABLE *table,
+ List<String> *index_list);
bool insert_fields(THD *thd,TABLE_LIST *tables,
const char *db_name, const char *table_name,
List_iterator<Item> *it);
@@ -643,7 +748,7 @@ bool setup_tables(TABLE_LIST *tables);
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list, uint wild_num);
int setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables,
- List<Item> &item, bool set_query_id,
+ List<Item> &item, bool set_query_id,
List<Item> *sum_func_list, bool allow_sum_func);
void unfix_item_list(List<Item> item_list);
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 62f2471d34f..1bfb8e8cbf1 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2114,7 +2114,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
global_system_variables.character_set_results= default_charset_info;
global_system_variables.character_set_client= default_charset_info;
- if (use_temp_pool && bitmap_init(&temp_pool,1024,1))
+ if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1))
return 1;
return 0;
}
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 24768537e3d..a8ea50beafc 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -304,7 +304,7 @@ static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree,
static QUICK_SELECT *get_quick_select(PARAM *param,uint index,
SEL_ARG *key_tree);
#ifndef DBUG_OFF
-static void print_quick(QUICK_SELECT *quick,key_map needed_reg);
+static void print_quick(QUICK_SELECT *quick,const key_map& needed_reg);
#endif
static SEL_TREE *tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
static SEL_TREE *tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
@@ -363,7 +363,6 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
SQL_SELECT::SQL_SELECT() :quick(0),cond(0),free_cond(0)
{
- quick_keys=0; needed_reg=0;
my_b_clear(&file);
}
@@ -584,18 +583,18 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
uint idx;
double scan_time;
DBUG_ENTER("test_quick_select");
- DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
+/* DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
(ulong) keys_to_use, (ulong) prev_tables,
- (ulong) const_tables));
+ (ulong) const_tables));*/
delete quick;
quick=0;
- needed_reg=0; quick_keys=0;
+ needed_reg.clear_all(); quick_keys.clear_all();
if (!cond || (specialflag & SPECIAL_SAFE_MODE) && ! force_quick_range ||
!limit)
DBUG_RETURN(0); /* purecov: inspected */
if (!((basflag= head->file->table_flags()) & HA_KEYPOS_TO_RNDPOS) &&
- keys_to_use == (uint) ~0 || !keys_to_use)
+ keys_to_use.is_set_all() || keys_to_use.is_clear_all())
DBUG_RETURN(0); /* Not smart database */
records=head->file->records;
if (!records)
@@ -611,8 +610,8 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
DBUG_PRINT("info",("Time to scan table: %g", read_time));
- keys_to_use&=head->keys_in_use_for_query;
- if (keys_to_use)
+ keys_to_use.intersect(head->keys_in_use_for_query);
+ if (!keys_to_use.is_clear_all())
{
MEM_ROOT *old_root,alloc;
SEL_TREE *tree;
@@ -645,7 +644,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
for (idx=0 ; idx < head->keys ; idx++)
{
- if (!(keys_to_use & ((key_map) 1L << idx)))
+ if (!keys_to_use.is_set(idx))
continue;
KEY *key_info= &head->key_info[idx];
if (key_info->flags & HA_FULLTEXT)
@@ -661,7 +660,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
key_parts->null_bit= key_info->key_part[part].null_bit;
if (key_parts->field->type() == FIELD_TYPE_BLOB)
key_parts->part_length+=HA_KEY_BLOB_LENGTH;
- key_parts->image_type =
+ key_parts->image_type =
(key_info->flags & HA_SPATIAL) ? Field::itMBR : Field::itRAW;
}
param.real_keynr[param.keys++]=idx;
@@ -692,11 +691,11 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
uint keynr= param.real_keynr[idx];
if ((*key)->type == SEL_ARG::MAYBE_KEY ||
(*key)->maybe_flag)
- needed_reg|= (key_map) 1 << keynr;
+ needed_reg.set_bit(keynr);
found_records=check_quick_select(&param, idx, *key);
if (found_records != HA_POS_ERROR && found_records > 2 &&
- head->used_keys & ((table_map) 1 << keynr) &&
+ head->used_keys.is_set(keynr) &&
(head->file->index_flags(keynr) & HA_KEY_READ_ONLY))
{
/*
@@ -2100,7 +2099,7 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree)
if (records != HA_POS_ERROR)
{
uint key=param->real_keynr[idx];
- param->table->quick_keys|= (key_map) 1 << key;
+ param->table->quick_keys.set_bit(key);
param->table->quick_rows[key]=records;
param->table->quick_key_parts[key]=param->max_key_part+1;
}
@@ -2841,17 +2840,18 @@ print_key(KEY_PART *key_part,const char *key,uint used_length)
}
}
-static void print_quick(QUICK_SELECT *quick,key_map needed_reg)
+static void print_quick(QUICK_SELECT *quick,const key_map& needed_reg)
{
QUICK_RANGE *range;
+ char buf[MAX_KEY/8+1];
DBUG_ENTER("print_param");
if (! _db_on_ || !quick)
DBUG_VOID_RETURN;
List_iterator<QUICK_RANGE> li(quick->ranges);
DBUG_LOCK_FILE;
- fprintf(DBUG_FILE,"Used quick_range on key: %d (other_keys: %lu):\n",
- quick->index, (ulong) needed_reg);
+ fprintf(DBUG_FILE,"Used quick_range on key: %d (other_keys: %s):\n",
+ quick->index, needed_reg.print(buf));
while ((range=li++))
{
if (!(range->flag & NO_MIN_RANGE))
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 00736bfc22f..4931f6f007e 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -128,7 +128,7 @@ class SQL_SELECT :public Sql_alloc {
SQL_SELECT();
~SQL_SELECT();
bool check_quick(bool force_quick_range=0, ha_rows limit = HA_POS_ERROR)
- { return test_quick_select(~0L,0,limit, force_quick_range) < 0; }
+ { return test_quick_select(key_map(~0),0,limit, force_quick_range) < 0; }
inline bool skipp_record() { return cond ? cond->val_int() == 0 : 0; }
int test_quick_select(key_map keys,table_map prev_tables,ha_rows limit,
bool force_quick_range=0);
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 34cce98d087..932aceebdbb 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -683,7 +683,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
The following test is false when the key in the key tree is
converted (for example to upper case)
*/
- if (field->part_of_key & ((key_map) 1 << idx))
+ if (field->part_of_key.is_set(idx))
{
table->key_read= 1;
table->file->extra(HA_EXTRA_KEYREAD);
@@ -696,7 +696,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
return 0;
}
-
+
/*
Check whether found key is in range specified by conditions
@@ -707,7 +707,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
field in: Field used the MIN/MAX expression
cond in: WHERE condition
range_fl in: Says whether there is a condition to to be checked
- prefix_len in: Length of the constant part of the key
+ prefix_len in: Length of the constant part of the key
RETURN
0 ok
diff --git a/sql/slave.cc b/sql/slave.cc
index 3e98386bbb1..2aea1056ac8 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -330,7 +330,7 @@ err:
void init_slave_skip_errors(const char* arg)
{
const char *p;
- if (bitmap_init(&slave_error_mask,MAX_SLAVE_ERROR,0))
+ if (bitmap_init(&slave_error_mask,0,MAX_SLAVE_ERROR,0))
{
fprintf(stderr, "Badly out of memory, please check your system status\n");
exit(1);
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 179da6096de..a47a38f2376 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -3545,8 +3545,16 @@ int mysql_revoke_all(THD *thd, List <LEX_USER> &list)
VOID(pthread_mutex_unlock(&acl_cache->lock));
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
+
+ /* XXX this should not be necessary. The error message is already printed
+ by replace_xxx_table. my_error() should be use above instead of
+ sql_print_error(), and print ER_NONEXISTING_GRANT - as other grant
+ commands do */
+ /* when this code is deleted, the error slot (error 1268) can be reused,
+ as this error code was not present in any MySQL release */
if (result)
my_error(ER_REVOKE_GRANTS, MYF(0));
+
DBUG_RETURN(result);
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index a926c6e66fe..b151400db68 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1675,7 +1675,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
goto found;
}
}
- if (allow_rowid &&
+ if (allow_rowid &&
!my_strcasecmp(system_charset_info, name, "_rowid") &&
(field=table->rowid_field))
goto found;
@@ -1688,7 +1688,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
{
field->query_id=thd->query_id;
table->used_fields++;
- table->used_keys&= field->part_of_key;
+ table->used_keys.intersect(field->part_of_key);
}
else
thd->dupp_field=field;
@@ -1717,7 +1717,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
RETURN VALUES
0 Field is not found or field is not unique- error
message is reported
- not_found_field Function was called with report_error == FALSE and
+ not_found_field Function was called with report_error == FALSE and
field was not found. no error message reported.
found field
*/
@@ -2041,21 +2041,21 @@ bool setup_tables(TABLE_LIST *tables)
table->used_keys= table->keys_for_keyread;
if (table_list->use_index)
{
- key_map map= get_key_map_from_key_list(table,
- table_list->use_index);
- if (map == ~(key_map) 0)
+ key_map map;
+ get_key_map_from_key_list(&map, table, table_list->use_index);
+ if (map.is_set_all())
DBUG_RETURN(1);
table->keys_in_use_for_query=map;
}
if (table_list->ignore_index)
{
- key_map map= get_key_map_from_key_list(table,
- table_list->ignore_index);
- if (map == ~(key_map) 0)
+ key_map map;
+ get_key_map_from_key_list(&map, table, table_list->ignore_index);
+ if (map.is_set_all())
DBUG_RETURN(1);
- table->keys_in_use_for_query &= ~map;
+ table->keys_in_use_for_query.subtract(map);
}
- table->used_keys &= table->keys_in_use_for_query;
+ table->used_keys.intersect(table->keys_in_use_for_query);
if (table_list->shared || table->clear_query_id)
{
table->clear_query_id= 0;
@@ -2073,24 +2073,26 @@ bool setup_tables(TABLE_LIST *tables)
}
-key_map get_key_map_from_key_list(TABLE *table,
- List<String> *index_list)
+void get_key_map_from_key_list(key_map *map, TABLE *table,
+ List<String> *index_list)
{
- key_map map=0;
List_iterator_fast<String> it(*index_list);
String *name;
uint pos;
+
+ map->clear_all();
while ((name=it++))
{
if ((pos=find_type(name->c_ptr(), &table->keynames, 1+2)) <= 0)
{
my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), name->c_ptr(),
table->real_name);
- return (~ (key_map) 0);
+ map->set_all();
+ return;
}
- map|= ((key_map) 1) << (pos-1);
+ map->set_bit(pos-1);
}
- return map;
+ return;
}
/****************************************************************************
@@ -2135,7 +2137,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
if (field->query_id == thd->query_id)
thd->dupp_field=field;
field->query_id=thd->query_id;
- table->used_keys&= field->part_of_key;
+ table->used_keys.intersect(field->part_of_key);
}
/* All fields are used */
table->used_fields=table->fields;
@@ -2226,8 +2228,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
/* Mark field used for table cache */
t1->field[i]->query_id=t2->field[j]->query_id=thd->query_id;
cond_and->list.push_back(tmp);
- t1->used_keys&= t1->field[i]->part_of_key;
- t2->used_keys&= t2->field[j]->part_of_key;
+ t1->used_keys.intersect(t1->field[i]->part_of_key);
+ t2->used_keys.intersect(t2->field[j]->part_of_key);
break;
}
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 48ef5b4b74c..bd76cbd5f36 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -85,7 +85,8 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
/* Handler didn't support fast delete; Delete rows one by one */
}
- table->used_keys=table->quick_keys=0; // Can't use 'only index'
+ table->used_keys.clear_all();
+ table->quick_keys.clear_all(); // Can't use 'only index'
select=make_select(table,0,0,conds,&error);
if (error)
DBUG_RETURN(-1);
@@ -98,7 +99,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
}
/* If running in safe sql mode, don't allow updates without keys */
- if (!table->quick_keys)
+ if (table->quick_keys.is_clear_all())
{
thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
if (safe_update && !using_limit)
@@ -292,7 +293,7 @@ multi_delete::initialize_tables(JOIN *join)
walk=walk->next;
/* Don't use KEYREAD optimization on this table */
tbl->no_keyread=1;
- tbl->used_keys= 0;
+ tbl->used_keys.clear_all();
if (tbl->file->has_transactions())
log_delayed= transactional_tables= 1;
else if (tbl->tmp_table != NO_TMP_TABLE)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 4bab97d4a46..5bd494c723d 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -35,6 +35,9 @@ const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
"ref_or_null","unique_subquery","index_subquery"
};
+const key_map key_map_empty(0);
+const key_map key_map_full(~0);
+
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
DYNAMIC_ARRAY *keyuse);
@@ -114,7 +117,7 @@ static int join_read_next_same_or_null(READ_RECORD *info);
static COND *make_cond_for_table(COND *cond,table_map table,
table_map used_table);
static Item* part_of_refkey(TABLE *form,Field *field);
-static uint find_shortest_key(TABLE *table, key_map usable_keys);
+static uint find_shortest_key(TABLE *table, const key_map& usable_keys);
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
ha_rows select_limit, bool no_changes);
static int create_sort_index(THD *thd, JOIN *join, ORDER *order,
@@ -831,7 +834,7 @@ JOIN::optimize()
conds,
1)));
}
-
+
}
/*
Need to tell Innobase that to play it safe, it should fetch all
@@ -1558,7 +1561,7 @@ err:
JOIN *curr_join= (join->need_tmp&&join->tmp_join?
(join->tmp_join->error=join->error,join->tmp_join):
join);
-
+
thd->proc_info="end";
err= join->cleanup();
if (thd->net.report_error)
@@ -1575,7 +1578,7 @@ err:
*****************************************************************************/
static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table,
- key_map keys,ha_rows limit)
+ const key_map& keys,ha_rows limit)
{
int error;
DBUG_ENTER("get_quick_record_count");
@@ -1637,9 +1640,13 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
TABLE *table;
stat_vector[i]=s;
+ s->keys.init();
+ s->const_keys.init();
+ s->checked_keys.init();
+ s->needed_reg.init();
table_vector[i]=s->table=table=tables->table;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);// record count
- table->quick_keys=0;
+ table->quick_keys.clear_all();
table->reginfo.join_tab=s;
table->reginfo.not_exists_optimize=0;
bzero((char*) table->const_key_parts, sizeof(key_part_map)*table->keys);
@@ -1785,24 +1792,25 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
start_keyuse=keyuse;
key=keyuse->key;
- s->keys|= (key_map) 1 << key; // QQ: remove this ?
+ s->keys.set_bit(key); // QQ: remove this ?
- refs=const_ref=0;
- eq_part=0;
+ refs=0;
+ const_ref.clear_all();
+ eq_part.clear_all();
do
{
if (keyuse->val->type() != Item::NULL_ITEM && !keyuse->optimize)
{
if (!((~found_const_table_map) & keyuse->used_tables))
- const_ref|= (key_map) 1 << keyuse->keypart;
+ const_ref.set_bit(keyuse->keypart);
else
refs|=keyuse->used_tables;
- eq_part|= (key_map) 1 << keyuse->keypart;
+ eq_part.set_bit(keyuse->keypart);
}
keyuse++;
} while (keyuse->table == table && keyuse->key == key);
- if (eq_part == PREV_BITS(uint,table->key_info[key].key_parts) &&
+ if (eq_part.is_prefix(table->key_info[key].key_parts) &&
(table->key_info[key].flags & HA_NOSAME) &&
!table->fulltext_searched)
{
@@ -1858,7 +1866,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
if (s->worst_seeks < 2.0) // Fix for small tables
s->worst_seeks=2.0;
- if (s->const_keys)
+ if (! s->const_keys.is_clear_all())
{
ha_rows records;
SQL_SELECT *select;
@@ -2095,9 +2103,10 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
else
{
JOIN_TAB *stat=field->table->reginfo.join_tab;
- key_map possible_keys= (field->key_start &
- field->table->keys_in_use_for_query);
- stat[0].keys|= possible_keys; // Add possible keys
+ key_map possible_keys;
+ possible_keys=field->key_start;
+ possible_keys.intersect(field->table->keys_in_use_for_query);
+ stat[0].keys.merge(possible_keys); // Add possible keys
/*
Save the following cases:
@@ -2116,7 +2125,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
for (uint i=0; i<num_values; i++)
is_const&= (*value)->const_item();
if (is_const)
- stat[0].const_keys |= possible_keys;
+ stat[0].const_keys.merge(possible_keys);
/*
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.
@@ -2247,14 +2256,13 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
*/
static uint
-max_part_bit(key_map bits)
+max_part_bit(key_part_map bits)
{
uint found;
for (found=0; bits & 1 ; found++,bits>>=1) ;
return found;
}
-
static void
add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
{
@@ -2266,7 +2274,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
{
for (uint key=0 ; key < form->keys ; key++)
{
- if (!(form->keys_in_use_for_query & (((key_map) 1) << key)))
+ if (!(form->keys_in_use_for_query.is_set(key)))
continue;
if (form->key_info[key].flags & HA_FULLTEXT)
continue; // ToDo: ft-keys in non-ft queries. SerG
@@ -2457,7 +2465,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
/* Save ptr to first use */
if (!use->table->reginfo.join_tab->keyuse)
use->table->reginfo.join_tab->keyuse=save_pos;
- use->table->reginfo.join_tab->checked_keys|= (key_map) 1 << use->key;
+ use->table->reginfo.join_tab->checked_keys.set_bit(use->key);
save_pos++;
}
i=(uint) (save_pos-(KEYUSE*) keyuse->buffer);
@@ -2598,7 +2606,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; // Assumed records/key
for (keyuse=s->keyuse ; keyuse->table == table ;)
{
- key_map found_part=0;
+ key_part_map found_part=0;
table_map found_ref=0;
uint key=keyuse->key;
KEY *keyinfo=table->key_info+key;
@@ -2667,7 +2675,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
{
if (!found_ref)
{ // We found a const key
- if (table->quick_keys & ((key_map) 1 << key))
+ if (table->quick_keys.is_set(key))
records= (double) table->quick_rows[key];
else
{
@@ -2691,7 +2699,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
/* Limit the number of matched rows */
tmp= records;
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
- if (table->used_keys & ((key_map) 1 << key))
+ if (table->used_keys.is_set(key))
{
/* we can use only index tree */
uint keys_per_block= table->file->block_size/2/
@@ -2718,7 +2726,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
Check if quick_range could determinate how many rows we
will match
*/
- if (table->quick_keys & ((key_map) 1 << key) &&
+ if (table->quick_keys.is_set(key) &&
table->quick_key_parts[key] <= max_key_part)
tmp=records= (double) table->quick_rows[key];
else
@@ -2770,7 +2778,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
}
/* Limit the number of matched rows */
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
- if (table->used_keys & ((key_map) 1 << key))
+ if (table->used_keys.is_set(key))
{
/* we can use only index tree */
uint keys_per_block= table->file->block_size/2/
@@ -2809,7 +2817,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
!(s->quick && best_key && s->quick->index == best_key->key &&
best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&
!((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) &&
- s->table->used_keys && best_key) &&
+ ! s->table->used_keys.is_clear_all() && best_key) &&
!(s->table->force_index && best_key))
{ // Check full join
ha_rows rnd_records= s->found_records;
@@ -3023,7 +3031,7 @@ get_best_combination(JOIN *join)
if (j->type == JT_SYSTEM)
continue;
- if (!j->keys || !(keyuse= join->best_positions[tablenr].key))
+ if (j->keys.is_clear_all() || !(keyuse= join->best_positions[tablenr].key))
{
j->type=JT_ALL;
if (tablenr != join->const_tables)
@@ -3254,7 +3262,7 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join_tab->select_cond=0;
join_tab->quick=0;
join_tab->type= JT_ALL; /* Map through all records */
- join_tab->keys= (uint) ~0; /* test everything in quick */
+ join_tab->keys.init().set_all(); /* test everything in quick */
join_tab->info=0;
join_tab->on_expr=0;
join_tab->ref.key = -1;
@@ -3336,13 +3344,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
/* Use quick key read if it's a constant and it's not used
with key reading */
- if (tab->needed_reg == 0 && tab->type != JT_EQ_REF
+ if (tab->needed_reg.is_clear_all() && tab->type != JT_EQ_REF
&& tab->type != JT_FT && (tab->type != JT_REF ||
(uint) tab->ref.key == tab->quick->index))
{
sel->quick=tab->quick; // Use value from get_quick_...
- sel->quick_keys=0;
- sel->needed_reg=0;
+ sel->quick_keys.clear_all();
+ sel->needed_reg.clear_all();
}
else
{
@@ -3353,12 +3361,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
uint ref_key=(uint) sel->head->reginfo.join_tab->ref.key+1;
if (i == join->const_tables && ref_key)
{
- if (tab->const_keys && tab->table->reginfo.impossible_range)
+ if (!tab->const_keys.is_clear_all() &&
+ tab->table->reginfo.impossible_range)
DBUG_RETURN(1);
}
else if (tab->type == JT_ALL && ! use_quick_range)
{
- if (tab->const_keys &&
+ if (!tab->const_keys.is_clear_all() &&
tab->table->reginfo.impossible_range)
DBUG_RETURN(1); // Impossible range
/*
@@ -3368,9 +3377,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
the index if we are using limit and this is the first table
*/
- if ((tab->keys & ~ tab->const_keys && i > 0) ||
- (tab->const_keys && i == join->const_tables &&
- join->unit->select_limit_cnt <
+ if ((!tab->keys.is_subset(tab->const_keys) && i > 0) ||
+ (!tab->const_keys.is_clear_all() && i == join->const_tables &&
+ join->unit->select_limit_cnt <
join->best_positions[i].records_read &&
!(join->select_options & OPTION_FOUND_ROWS)))
{
@@ -3408,13 +3417,15 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
else
{
sel->needed_reg=tab->needed_reg;
- sel->quick_keys=0;
+ sel->quick_keys.clear_all();
}
- if ((sel->quick_keys | sel->needed_reg) & ~tab->checked_keys)
+ if (!sel->quick_keys.is_subset(tab->checked_keys) ||
+ !sel->needed_reg.is_subset(tab->checked_keys))
{
- tab->keys=sel->quick_keys | sel->needed_reg;
- tab->use_quick= (sel->needed_reg &&
- (!select->quick_keys ||
+ tab->keys=sel->quick_keys;
+ tab->keys.merge(sel->needed_reg);
+ tab->use_quick= (!sel->needed_reg.is_clear_all() &&
+ (select->quick_keys.is_clear_all() ||
(select->quick &&
(select->quick->records >= 100L)))) ?
2 : 1;
@@ -3479,7 +3490,7 @@ make_join_readinfo(JOIN *join, uint options)
table->file->index_init(tab->ref.key);
tab->read_first_record= join_read_key;
tab->read_record.read_record= join_no_more_records;
- if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
+ if (table->used_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@@ -3497,7 +3508,7 @@ make_join_readinfo(JOIN *join, uint options)
delete tab->quick;
tab->quick=0;
table->file->index_init(tab->ref.key);
- if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
+ if (table->used_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@@ -3572,12 +3583,12 @@ make_join_readinfo(JOIN *join, uint options)
if (!table->no_keyread)
{
if (tab->select && tab->select->quick &&
- table->used_keys & ((key_map) 1 << tab->select->quick->index))
+ table->used_keys.is_set(tab->select->quick->index))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
- else if (table->used_keys && ! (tab->select && tab->select->quick))
+ else if (!table->used_keys.is_clear_all() && ! (tab->select && tab->select->quick))
{ // Only read index tree
tab->index=find_shortest_key(table, table->used_keys);
tab->table->file->index_init(tab->index);
@@ -3923,7 +3934,7 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
DBUG_ENTER("return_zero_rows");
if (select_options & SELECT_DESCRIBE)
- {
+ {
select_describe(join, false, false, false, info);
DBUG_RETURN(0);
}
@@ -4653,6 +4664,12 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
table->db_low_byte_first=1; // True for HEAP and MyISAM
table->temp_pool_slot = temp_pool_slot;
table->copy_blobs= 1;
+ table->keys_for_keyread.init();
+ table->keys_in_use.init();
+ table->read_only_keys.init();
+ table->quick_keys.init();
+ table->used_keys.init();
+ table->keys_in_use_for_query.init();
/* Calculate which type of fields we will store in the temporary table */
@@ -5848,7 +5865,7 @@ join_read_first(JOIN_TAB *tab)
{
int error;
TABLE *table=tab->table;
- if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)) &&
+ if (!table->key_read && table->used_keys.is_set(tab->index) &&
!table->no_keyread)
{
table->key_read=1;
@@ -5885,7 +5902,7 @@ join_read_last(JOIN_TAB *tab)
{
TABLE *table=tab->table;
int error;
- if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)) &&
+ if (!table->key_read && table->used_keys.is_set(tab->index) &&
!table->no_keyread)
{
table->key_read=1;
@@ -6583,18 +6600,21 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
return reverse;
}
-static uint find_shortest_key(TABLE *table, key_map usable_keys)
+static uint find_shortest_key(TABLE *table, const key_map& usable_keys)
{
uint min_length= (uint) ~0;
uint best= MAX_KEY;
- for (uint nr=0; usable_keys ; usable_keys>>=1, nr++)
+ if (!usable_keys.is_clear_all())
{
- if (usable_keys & 1)
+ for (uint nr=0; nr < usable_keys.length() ; nr++)
{
- if (table->key_info[nr].key_length < min_length)
+ if (usable_keys.is_set(nr))
{
- min_length=table->key_info[nr].key_length;
- best=nr;
+ if (table->key_info[nr].key_length < min_length)
+ {
+ min_length=table->key_info[nr].key_length;
+ best=nr;
+ }
}
}
}
@@ -6640,7 +6660,7 @@ is_subkey(KEY_PART_INFO *key_part, KEY_PART_INFO *ref_key_part,
static uint
test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
- key_map usable_keys)
+ const key_map& usable_keys)
{
uint nr;
uint min_length= (uint) ~0;
@@ -6648,10 +6668,10 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
uint not_used;
KEY_PART_INFO *ref_key_part= table->key_info[ref].key_part;
KEY_PART_INFO *ref_key_part_end= ref_key_part + ref_key_parts;
-
- for (nr= 0; usable_keys; usable_keys>>= 1, nr++)
+
+ for (nr= 0; nr < usable_keys.length(); nr++)
{
- if ((usable_keys & 1) &&
+ if (usable_keys.is_set(nr) &&
table->key_info[nr].key_length < min_length &&
table->key_info[nr].key_parts >= ref_key_parts &&
is_subkey(table->key_info[nr].key_part, ref_key_part,
@@ -6689,16 +6709,17 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
LINT_INIT(ref_key_parts);
/* Check which keys can be used to resolve ORDER BY */
- usable_keys= ~(key_map) 0;
+ usable_keys.set_all();
for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next)
{
if ((*tmp_order->item)->type() != Item::FIELD_ITEM)
{
- usable_keys=0;
+ usable_keys.clear_all();
break;
}
- if (!(usable_keys&= (((Item_field*) (*tmp_order->item))->field->
- part_of_sortkey)))
+ usable_keys.intersect(
+ ((Item_field*) (*tmp_order->item))->field->part_of_sortkey);
+ if (usable_keys.is_clear_all())
break; // No usable keys
}
@@ -6724,7 +6745,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
int order_direction;
uint used_key_parts;
- if (!(usable_keys & ((key_map) 1 << ref_key)))
+ if (!usable_keys.is_set(ref_key))
{
/*
We come here when ref_key is not among usable_keys
@@ -6734,8 +6755,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
If using index only read, only consider other possible index only
keys
*/
- if (table->used_keys & (((key_map) 1 << ref_key)))
- usable_keys|= table->used_keys;
+ if (table->used_keys.is_set(ref_key))
+ usable_keys.merge(table->used_keys);
if ((new_ref_key= test_if_subkey(order, table, ref_key, ref_key_parts,
usable_keys)) < MAX_KEY)
{
@@ -6751,10 +6772,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
select->quick->init();
}
ref_key= new_ref_key;
- }
+ }
}
/* Check if we get the rows in requested sorted order by using the key */
- if ((usable_keys & ((key_map) 1 << ref_key)) &&
+ if (usable_keys.is_set(ref_key) &&
(order_direction = test_if_order_by_key(order,table,ref_key,
&used_key_parts)))
{
@@ -6805,7 +6826,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
/* check if we can use a key to resolve the group */
/* Tables using JT_NEXT are handled here */
uint nr;
- key_map keys=usable_keys;
+ key_map keys;
/*
If not used with LIMIT, only use keys if the whole query can be
@@ -6813,12 +6834,19 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
retrieving all rows through an index.
*/
if (select_limit >= table->file->records)
- keys&= (table->used_keys | table->file->keys_to_use_for_scanning());
+ {
+ keys=table->file->keys_to_use_for_scanning();
+ keys.merge(table->used_keys);
+ }
+ else
+ keys.set_all();
+
+ keys.intersect(usable_keys);
- for (nr=0; keys ; keys>>=1, nr++)
+ for (nr=0; nr < keys.length() ; nr++)
{
uint not_used;
- if (keys & 1)
+ if (keys.is_set(nr))
{
int flag;
if ((flag=test_if_order_by_key(order, table, nr, &not_used)))
@@ -6830,7 +6858,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
join_read_last);
table->file->index_init(nr);
tab->type=JT_NEXT; // Read with index_first(), index_next()
- if (table->used_keys & ((key_map) 1 << nr))
+ if (table->used_keys.is_set(nr))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
@@ -6855,7 +6883,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
order How table should be sorted
filesort_limit Max number of rows that needs to be sorted
select_limit Max number of rows in final output
- Used to decide if we should use index or not
+ Used to decide if we should use index or not
IMPLEMENTATION
@@ -8684,7 +8712,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
Item *item_null= new Item_null();
CHARSET_INFO *cs= &my_charset_latin1;
DBUG_ENTER("select_describe");
- DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
+ DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
(ulong)join->select_lex, join->select_lex->type,
message));
/* Don't log this into the slow query log */
@@ -8718,7 +8746,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
tmp2.length(0);
item_list.empty();
- item_list.push_back(new Item_int((int32)
+ item_list.push_back(new Item_int((int32)
join->select_lex->select_number));
item_list.push_back(new Item_string(join->select_lex->type,
strlen(join->select_lex->type),
@@ -8740,21 +8768,23 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
item_list.push_back(new Item_string(join_type_str[tab->type],
strlen(join_type_str[tab->type]),
cs));
- key_map bits;
uint j;
- for (j=0,bits=tab->keys ; bits ; j++,bits>>=1)
+ if (!tab->keys.is_clear_all())
{
- if (bits & 1)
- {
- if (tmp1.length())
- tmp1.append(',');
- tmp1.append(table->key_info[j].name);
- }
+ for (j=0 ; j < tab->keys.length() ; j++)
+ {
+ if (tab->keys.is_set(j))
+ {
+ if (tmp1.length())
+ tmp1.append(',');
+ tmp1.append(table->key_info[j].name);
+ }
+ }
}
if (tmp1.length())
item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs));
else
- item_list.push_back(item_null);
+ item_list.push_back(item_null);
if (tab->ref.key_parts)
{
KEY *key_info=table->key_info+ tab->ref.key;
@@ -8797,10 +8827,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
join->best_positions[i]. records_read,
21));
my_bool key_read=table->key_read;
- if (tab->type == JT_NEXT &&
- ((table->used_keys & ((key_map) 1 << tab->index))))
+ if (tab->type == JT_NEXT && table->used_keys.is_set(tab->index))
key_read=1;
-
+
if (tab->info)
item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
else
@@ -8809,8 +8838,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
{
if (tab->use_quick == 2)
{
- sprintf(buff_ptr,"; Range checked for each record (index map: %u)",
- tab->keys);
+ char buf[MAX_KEY/8+1];
+ sprintf(buff_ptr,"; Range checked for each record (index map: %s)",
+ tab->keys.print(buf));
buff_ptr=strend(buff_ptr);
}
else
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 6c17a646ee6..aa77722546d 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -29,8 +29,8 @@ typedef struct keyuse_t {
Item *val; /* or value if no field */
table_map used_tables;
uint key, keypart, optimize;
- key_map keypart_map;
- ha_rows ref_table_rows;
+ key_part_map keypart_map;
+ ha_rows ref_table_rows;
} KEYUSE;
class store_key;
@@ -96,9 +96,9 @@ typedef struct st_join_table {
key_map const_keys; /* Keys with constant part */
key_map checked_keys; /* Keys checked in find_best */
key_map needed_reg;
+ key_map keys; /* all keys with can be used */
ha_rows records,found_records,read_time;
table_map dependent,key_dependent;
- uint keys; /* all keys with can be used */
uint use_quick,index;
uint status; // Save status for cache
uint used_fields,used_fieldlength,used_blobs;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 8550973ff88..a026bd5276d 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -939,7 +939,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
protocol->store((const char*) pos, system_charset_info);
protocol->store(table->file->index_type(i), system_charset_info);
/* Comment */
- if (!(table->keys_in_use & ((key_map) 1 << i)))
+ if (!table->keys_in_use.is_set(i))
protocol->store("disabled",8, system_charset_info);
else
protocol->store("", 0, system_charset_info);
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index f991a09398b..006a324f16d 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -172,10 +172,11 @@ TEST_join(JOIN *join)
tab->ref.key_length);
if (tab->select)
{
+ char buf[MAX_KEY/8+1];
if (tab->use_quick == 2)
fprintf(DBUG_FILE,
- " quick select checked for each record (keys: %d)\n",
- (int) tab->select->quick_keys);
+ " quick select checked for each record (keys: %s)\n",
+ tab->select->quick_keys.print(buf));
else if (tab->select->quick)
fprintf(DBUG_FILE," quick select used on key %s, length: %d\n",
form->key_info[tab->select->quick->index].name,
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 2ecc526a612..4cf5f740d17 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -85,7 +85,7 @@ int mysql_update(THD *thd,
/* Calculate "table->used_keys" based on the WHERE */
table->used_keys=table->keys_in_use;
- table->quick_keys=0;
+ table->quick_keys.clear_all();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
want_privilege=table->grant.want_privilege;
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
@@ -149,7 +149,7 @@ int mysql_update(THD *thd,
}
// Don't count on usage of 'only index' when calculating which key to use
- table->used_keys=0;
+ table->used_keys.clear_all();
select=make_select(table,0,0,conds,&error);
if (error ||
(select && select->check_quick(safe_update, limit)) || !limit)
@@ -164,7 +164,7 @@ int mysql_update(THD *thd,
DBUG_RETURN(0);
}
/* If running in safe sql mode, don't allow updates without keys */
- if (!table->quick_keys)
+ if (table->quick_keys.is_clear_all())
{
thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
if (safe_update && !using_limit)
@@ -192,7 +192,7 @@ int mysql_update(THD *thd,
matching rows before updating the table!
*/
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (old_used_keys & ((key_map) 1 << used_index))
+ if (old_used_keys.is_set(used_index))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
@@ -501,8 +501,7 @@ int multi_update::prepare(List<Item> &not_used_values, SELECT_LEX_UNIT *unit)
if (!tables_to_update)
{
- my_error(ER_NOT_SUPPORTED_YET, MYF(0),
- "You didn't specify any tables to UPDATE");
+ my_error(ER_NO_TABLES_USED, MYF(0));
DBUG_RETURN(1);
}
@@ -533,7 +532,7 @@ int multi_update::prepare(List<Item> &not_used_values, SELECT_LEX_UNIT *unit)
update.link_in_list((byte*) tl, (byte**) &tl->next);
tl->shared= table_count++;
table->no_keyread=1;
- table->used_keys=0;
+ table->used_keys.clear_all();
table->pos_in_table_list= tl;
}
}
diff --git a/sql/table.cc b/sql/table.cc
index c31b68fc2dc..c6da3432aaa 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -137,10 +137,11 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
outparam->raid_type= head[41];
outparam->raid_chunks= head[42];
outparam->raid_chunksize= uint4korr(head+43);
- if (!(outparam->table_charset=get_charset((uint) head[38],MYF(0))))
- outparam->table_charset=default_charset_info; // QQ display error message?
+ outparam->table_charset=get_charset((uint) head[38],MYF(0));
null_field_first=1;
}
+ if (!outparam->table_charset) /* unknown charset in head[38] or pre-3.23 frm */
+ outparam->table_charset=default_charset_info;
outparam->db_record_offset=1;
if (db_create_options & HA_OPTION_LONG_BLOB_PTR)
outparam->blob_ptr_size=portable_sizeof_char_ptr;
@@ -156,7 +157,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (read_string(file,(gptr*) &disk_buff,key_info_length))
goto err_not_open; /* purecov: inspected */
outparam->keys=keys= disk_buff[0];
- outparam->keys_for_keyread= outparam->keys_in_use= set_bits(key_map, keys);
+ outparam->keys_for_keyread.init().set_prefix(keys);
+ outparam->keys_in_use.init().set_prefix(keys);
+ outparam->read_only_keys.init().clear_all();
+ outparam->quick_keys.init();
+ outparam->used_keys.init();
+ outparam->keys_in_use_for_query.init();
outparam->key_parts=key_parts=disk_buff[1];
n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO);
@@ -484,8 +490,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
index_flags=outparam->file->index_flags(key);
if (!(index_flags & HA_KEY_READ_ONLY))
{
- outparam->read_only_keys|= ((key_map) 1 << key);
- outparam->keys_for_keyread&= ~((key_map) 1 << key);
+ outparam->read_only_keys.set_bit(key);
+ outparam->keys_for_keyread.clear_bit(key);
}
if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME))
@@ -545,7 +551,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
field->key_length() ==
keyinfo->key_length ? UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG);
if (i == 0)
- field->key_start|= ((key_map) 1 << key);
+ field->key_start.set_bit(key);
if (field->key_length() == key_part->length &&
!(field->flags & BLOB_FLAG))
{
@@ -553,11 +559,11 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
(field->key_type() != HA_KEYTYPE_TEXT ||
(!(ha_option & HA_KEY_READ_WRONG_STR) &&
!(keyinfo->flags & HA_FULLTEXT))))
- field->part_of_key|= ((key_map) 1 << key);
+ field->part_of_key.set_bit(key);
if ((field->key_type() != HA_KEYTYPE_TEXT ||
!(keyinfo->flags & HA_FULLTEXT)) &&
!(index_flags & HA_WRONG_ASCII_ORDER))
- field->part_of_sortkey|= ((key_map) 1 << key);
+ field->part_of_sortkey.set_bit(key);
}
if (!(key_part->key_part_flag & HA_REVERSE_SORT) &&
usable_parts == i)
@@ -600,7 +606,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
keyinfo->usable_key_parts=usable_parts; // Filesort
}
if (primary_key < MAX_KEY &&
- (outparam->keys_in_use & ((key_map) 1 << primary_key)))
+ (outparam->keys_in_use.is_set(primary_key)))
{
outparam->primary_key=primary_key;
/*
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 3e634f54b4f..be14448bd1d 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -33,7 +33,7 @@
static uchar * pack_screens(List<create_field> &create_fields,
uint *info_length, uint *screens, bool small_file);
static uint pack_keys(uchar *keybuff,uint key_count, KEY *key_info);
-static bool pack_header(uchar *forminfo, enum db_type table_type,
+static bool pack_header(uchar *forminfo,enum db_type table_type,
List<create_field> &create_fields,
uint info_length, uint screens, uint table_options,
handler *file);