Commit 954264b1 authored by unknown's avatar unknown

merged

BitKeeper/etc/ignore:
  auto-union
include/m_ctype.h:
  Auto merged
mysql-test/r/mysqldump.result:
  Auto merged
sql/field.cc:
  Auto merged
sql/ha_berkeley.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/opt_range.cc:
  Auto merged
sql/slave.cc:
  Auto merged
sql/sql_acl.cc:
  Auto merged
sql/sql_delete.cc:
  Auto merged
sql/sql_select.cc:
  Auto merged
sql/sql_show.cc:
  Auto merged
sql/sql_table.cc:
  Auto merged
sql/sql_test.cc:
  Auto merged
sql/sql_update.cc:
  Auto merged
sql/sql_yacc.yy:
  Auto merged
sql/table.cc:
  Auto merged
strings/ctype-simple.c:
  Auto merged
parents 8c2d17c7 572e18ae
......@@ -591,6 +591,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
......
......@@ -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;
......
......@@ -310,6 +310,7 @@ int my_wildcmp_8bit(CHARSET_INFO *,
uint my_numchars_8bit(CHARSET_INFO *, const char *b, const char *e);
uint my_charpos_8bit(CHARSET_INFO *, const char *b, const char *e, uint pos);
int my_mbcharlen_8bit(CHARSET_INFO *, uint c);
/* Functions for multibyte charsets */
......
......@@ -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
......
......@@ -230,7 +230,7 @@
#define ER_NO_PERMISSION_TO_CREATE_USER 1211
#define ER_UNION_TABLES_IN_DIFFERENT_DIR 1212
#define ER_LOCK_DEADLOCK 1213
#define ER_TABLE_CANT_HANDLE_FULLTEXT 1214
#define ER_TABLE_CANT_HANDLE_FT 1214
#define ER_CANNOT_ADD_FOREIGN 1215
#define ER_NO_REFERENCED_ROW 1216
#define ER_ROW_IS_REFERENCED 1217
......@@ -296,4 +296,5 @@
#define ER_MISSING_SKIP_SLAVE 1277
#define ER_UNTIL_COND_IGNORED 1278
#define ER_WRONG_INDEX_NAME 1279
#define ER_ERROR_MESSAGES 280
#define ER_BAD_FT_COLUMN 1280
#define ER_ERROR_MESSAGES 281
......@@ -144,7 +144,7 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
param.prev=' ';
param.quot=up->quot;
while ((res=ft_get_word(start,end,&w,&param)))
while ((res=ft_get_word(ftb->charset,start,end,&w,&param)))
{
int r=param.plusminus;
float weight= (float) (param.pmsign ? nwghts : wghts)[(r>5)?5:((r<-5)?-5:r)];
......@@ -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));
......@@ -350,8 +354,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query,
ftb->info=info;
ftb->keynr=keynr;
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->lastpos=HA_POS_ERROR;
bzero(& ftb->no_dupes, sizeof(TREE));
......@@ -387,25 +390,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;
......@@ -596,7 +608,8 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length)
continue;
end=ftsi.pos+ftsi.len;
while (ft_simple_get_word((byte **) &ftsi.pos,(byte *) end, &word))
while (ft_simple_get_word(ftb->charset,
(byte **) &ftsi.pos, (byte *) end, &word))
{
int a, b, c;
for (a=0, b=ftb->queue.elements, c=(a+b)/2; b-a>1; c=(a+b)/2)
......
......@@ -73,25 +73,17 @@ 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
* 2 - left bracket
* 3 - right bracket
*/
byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param)
byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end,
FT_WORD *word, FTB_PARAM *param)
{
byte *doc=*start;
int mwc;
uint mwc, length;
param->yesno=(FTB_YES==' ') ? 1 : (param->quot != 0);
param->plusminus=param->pmsign=0;
......@@ -100,11 +92,7 @@ byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param)
{
for (;doc<end;doc++)
{
/*
BAR TODO: discuss with Serge how to remove
default_charset_info correctly
*/
if (true_word_char(default_charset_info,*doc)) break;
if (true_word_char(cs,*doc)) break;
if (*doc == FTB_RQUOT && param->quot) {
param->quot=doc;
*start=doc+1;
......@@ -132,9 +120,9 @@ byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param)
param->plusminus=param->pmsign=0;
}
mwc=0;
for (word->pos=doc; doc<end; doc++)
if (true_word_char(default_charset_info,*doc))
mwc=length=0;
for (word->pos=doc; doc<end; length++, doc+=my_mbcharlen(cs, *(uchar *)doc))
if (true_word_char(cs,*doc))
mwc=0;
else if (!misc_word_char(*doc) || mwc++)
break;
......@@ -144,8 +132,8 @@ byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param)
if ((param->trunc=(doc<end && *doc == FTB_TRUNC)))
doc++;
if (((word->len >= ft_min_word_len && !is_stopword(word->pos, word->len))
|| param->trunc) && word->len < ft_max_word_len)
if (((length >= ft_min_word_len && !is_stopword(word->pos, word->len))
|| param->trunc) && length < ft_max_word_len)
{
*start=doc;
return 1;
......@@ -154,29 +142,30 @@ byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param)
return 0;
}
byte ft_simple_get_word(byte **start, byte *end, FT_WORD *word)
byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, byte *end,
FT_WORD *word)
{
byte *doc=*start;
int mwc;
uint mwc, length;
DBUG_ENTER("ft_simple_get_word");
while (doc<end)
{
for (;doc<end;doc++)
{
if (true_word_char(default_charset_info,*doc)) break;
if (true_word_char(cs,*doc)) break;
}
mwc=0;
for(word->pos=doc; doc<end; doc++)
if (true_word_char(default_charset_info,*doc))
mwc=length=0;
for(word->pos=doc; doc<end; length++, doc+=my_mbcharlen(cs, *(uchar *)doc))
if (true_word_char(cs,*doc))
mwc=0;
else if (!misc_word_char(*doc) || mwc++)
break;
word->len= (uint)(doc-word->pos) - mwc;
if (word->len >= ft_min_word_len && word->len < ft_max_word_len &&
if (length >= ft_min_word_len && length < ft_max_word_len &&
!is_stopword(word->pos, word->len))
{
*start=doc;
......@@ -200,7 +189,7 @@ int ft_parse(TREE *wtree, byte *doc, int doclen)
FT_WORD w;
DBUG_ENTER("ft_parse");
while (ft_simple_get_word(&doc,end,&w))
while (ft_simple_get_word(wtree->custom_arg, &doc,end,&w))
{
if (!tree_insert(wtree, &w, 0, wtree->custom_arg))
goto err;
......
......@@ -81,7 +81,7 @@ int ft_init_stopwords()
goto err0;
len=my_read(fd, buffer, len, MYF(MY_WME));
end=start+len;
while (ft_simple_get_word(&start, end, &w))
while (ft_simple_get_word(default_charset_info, &start, end, &w))
{
if (ft_add_stopword(my_strdup_with_length(w.pos, w.len, MYF(0))))
goto err1;
......
......@@ -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;
......@@ -123,9 +114,7 @@ uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record)
DBUG_RETURN(0);
}
FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr,
byte *keybuf __attribute__((unused)),
const byte *record)
FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, const byte *record)
{
TREE ptree;
DBUG_ENTER("_mi_ft_parserecord");
......@@ -208,9 +197,9 @@ int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf,
int cmp, cmp2;
DBUG_ENTER("_mi_ft_update");
if (!(old_word=oldlist=_mi_ft_parserecord(info, keynr, keybuf, oldrec)))
if (!(old_word=oldlist=_mi_ft_parserecord(info, keynr, oldrec)))
goto err0;
if (!(new_word=newlist=_mi_ft_parserecord(info, keynr, keybuf, newrec)))
if (!(new_word=newlist=_mi_ft_parserecord(info, keynr, newrec)))
goto err1;
error=0;
......@@ -258,7 +247,7 @@ int _mi_ft_add(MI_INFO *info, uint keynr, byte *keybuf, const byte *record,
FT_WORD *wlist;
DBUG_ENTER("_mi_ft_add");
if ((wlist=_mi_ft_parserecord(info, keynr, keybuf, record)))
if ((wlist=_mi_ft_parserecord(info, keynr, record)))
{
error=_mi_ft_store(info,keynr,keybuf,wlist,pos);
my_free((char*) wlist,MYF(0));
......@@ -277,7 +266,7 @@ int _mi_ft_del(MI_INFO *info, uint keynr, byte *keybuf, const byte *record,
DBUG_ENTER("_mi_ft_del");
DBUG_PRINT("enter",("keynr: %d",keynr));
if ((wlist=_mi_ft_parserecord(info, keynr, keybuf, record)))
if ((wlist=_mi_ft_parserecord(info, keynr, record)))
{
error=_mi_ft_erase(info,keynr,keybuf,wlist,pos);
my_free((char*) wlist,MYF(0));
......@@ -305,3 +294,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));
}
......@@ -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
......@@ -107,8 +108,8 @@ int is_stopword(char *word, uint len);
uint _ft_make_key(MI_INFO *, uint , byte *, FT_WORD *, my_off_t);
byte ft_get_word(byte **, byte *, FT_WORD *, FTB_PARAM *);
byte ft_simple_get_word(byte **, byte *, FT_WORD *);
byte ft_get_word(CHARSET_INFO *, byte **, byte *, FT_WORD *, FTB_PARAM *);
byte ft_simple_get_word(CHARSET_INFO *, byte **, byte *, FT_WORD *);
typedef struct _st_ft_seg_iterator {
uint num, len;
......@@ -123,7 +124,7 @@ uint _mi_ft_segiterator(FT_SEG_ITERATOR *);
void ft_parse_init(TREE *, CHARSET_INFO *);
int ft_parse(TREE *, byte *, int);
FT_WORD * ft_linearize(TREE *);
FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, byte *, const byte *);
FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, const byte *);
uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record);
extern const struct _ft_vft _ft_vft_nlq;
......
......@@ -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 *);
......@@ -2575,8 +2575,7 @@ static int sort_ft_key_read(MI_SORT_PARAM *sort_param, void *key)
my_free((char*) wptr, MYF(MY_ALLOW_ZERO_PTR));
if ((error=sort_get_next_record(sort_param)))
DBUG_RETURN(error);
if (!(wptr=_mi_ft_parserecord(info,sort_param->key,
key,sort_param->record)))
if (!(wptr=_mi_ft_parserecord(info,sort_param->key,sort_param->record)))
DBUG_RETURN(1);
if (wptr->pos)
break;
......
......@@ -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;
......
......@@ -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
......
......@@ -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;
......
......@@ -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,
......
......@@ -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
......@@ -190,6 +191,12 @@ ticket inhalt
select * from t2 having MATCH inhalt AGAINST ('foobar');
ticket inhalt
3 foobar
CREATE TABLE t3 (t int(11),i text,fulltext tix (t,i));
ERROR HY000: Column 't' cannot be part of FULLTEXT index
CREATE TABLE t3 (t int(11),i text,
j varchar(200) CHARACTER SET latin2,
fulltext tix (i,j));
ERROR HY000: Column 'j' cannot be part of FULLTEXT index
CREATE TABLE t3 (
ticket int(11),
inhalt text,
......@@ -272,3 +279,24 @@ select * from t1 join t2 using(`t1_id`) where match (t1.name, t2.name) against('
t1_id name t2_id t1_id name
1 data1 1 1 xxfoo
drop table t1,t2;
SET NAMES latin1;
CREATE TABLE t1 (t text character set utf8 not null, fulltext(t));
INSERT t1 VALUES ('Mit freundlichem Gr'), ('aus Osnabrck');
SET NAMES koi8r;
INSERT t1 VALUES (" - "),(", !"),
(" , !"),(" !");
SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('');
t charset(t)
- utf8
SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('*' IN BOOLEAN MODE);
t charset(t)
! utf8
SELECT * FROM t1 WHERE MATCH t AGAINST ('' IN BOOLEAN MODE);
t
SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('Osnabrck');
t charset(t)
SET NAMES latin1;
SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('Osnabrck');
t charset(t)
aus Osnabrck utf8
DROP TABLE t1;
......@@ -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;
......@@ -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:
......@@ -129,6 +130,13 @@ select * from t2 having MATCH inhalt AGAINST ('foobar');
# check of fulltext errors
#
--error 1279
CREATE TABLE t3 (t int(11),i text,fulltext tix (t,i));
--error 1279
CREATE TABLE t3 (t int(11),i text,
j varchar(200) CHARACTER SET latin2,
fulltext tix (i,j));
CREATE TABLE t3 (
ticket int(11),
inhalt text,
......@@ -218,3 +226,21 @@ insert into t2 values (2, 1, 'xxbar');
insert into t2 values (3, 1, 'xxbuz');
select * from t1 join t2 using(`t1_id`) where match (t1.name, t2.name) against('xxfoo' in boolean mode);
drop table t1,t2;
#
# UTF8
#
SET NAMES latin1;
CREATE TABLE t1 (t text character set utf8 not null, fulltext(t));
INSERT t1 VALUES ('Mit freundlichem Gr'), ('aus Osnabrck');
SET NAMES koi8r;
INSERT t1 VALUES (" - "),(", !"),
(" , !"),(" !");
SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('');
SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('*' IN BOOLEAN MODE);
SELECT * FROM t1 WHERE MATCH t AGAINST ('' IN BOOLEAN MODE);
SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('Osnabrck');
SET NAMES latin1;
SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('Osnabrck');
DROP TABLE t1;
......@@ -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;
......@@ -39,7 +39,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\
mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \
my_symlink.c my_symlink2.c \
mf_pack.c mf_unixpath.c mf_strip.c \
mf_soundex.c mf_wcomp.c mf_wfile.c \
mf_wcomp.c mf_wfile.c \
mf_qsort.c mf_qsort2.c mf_sort.c \
ptr_cmp.c mf_radix.c queues.c \
tree.c list.c hash.c array.c string.c typelib.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);
}
......@@ -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;
......
......@@ -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);
......
......@@ -844,7 +844,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 */
......@@ -855,7 +855,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)
......@@ -868,7 +868,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
......@@ -885,12 +885,12 @@ int ha_berkeley::write_row(byte * record)
DBUG_PRINT("trans",("aborting subtransaction")); /* purecov: deadcode */
new_error=txn_abort(sub_trans); /* purecov: deadcode */
}
else if (changed_keys)
else if (!changed_keys.is_clear_all())
{
new_error = 0;
for (uint keynr=0; changed_keys; keynr++, changed_keys >>= 1)
for (uint keynr=0; keynr < changed_keys.length(); keynr++)
{
if (changed_keys & 1)
if (changed_keys.is_set(keynr))
{
if ((new_error = remove_key(sub_trans, keynr, record,
&prim_key)))
......@@ -1034,18 +1034,22 @@ int ha_berkeley::restore_keys(DB_TXN *trans, key_map changed_keys,
rolled back. The last key set in changed_keys is the one that
triggered the duplicate key error (it wasn't inserted), so for
that one just put back the old value. */
for (keynr=0; changed_keys; keynr++, changed_keys >>= 1)
if (!changed_keys.is_clear_all())
{
if (changed_keys & 1)
key_map map1(1);
for (keynr=0; keynr < changed_keys.length(); keynr++)
{
if (changed_keys != 1 &&
(error = remove_key(trans, keynr, new_row, new_key)))
break; /* purecov: inspected */
if ((error = key_file[keynr]->put(key_file[keynr], trans,
create_key(&tmp_key, keynr, key_buff2,
old_row),
old_key, key_type[keynr])))
break; /* purecov: inspected */
if (changed_keys.is_set(keynr))
{
if (changed_keys.is_subset(map1) &&
(error = remove_key(trans, keynr, new_row, new_key)))
break; /* purecov: inspected */
if ((error = key_file[keynr]->put(key_file[keynr], trans,
create_key(&tmp_key, keynr, key_buff2,
old_row),
old_key, key_type[keynr])))
break; /* purecov: inspected */
}
}
}
......@@ -1090,7 +1094,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 */
......@@ -1123,7 +1127,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),
......@@ -1147,7 +1151,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
DBUG_PRINT("trans",("aborting subtransaction")); /* purecov: deadcode */
new_error=txn_abort(sub_trans); /* purecov: deadcode */
}
else if (changed_keys)
else if (!changed_keys.is_clear_all())
new_error=restore_keys(transaction, changed_keys, primary_key,
old_row, &old_prim_key, new_row, &prim_key,
thd_options);
......@@ -1232,9 +1236,9 @@ int ha_berkeley::remove_keys(DB_TXN *trans, const byte *record,
DBT *new_record, DBT *prim_key, key_map keys)
{
int result = 0;
for (uint keynr=0; keys; keynr++, keys>>=1)
for (uint keynr=0; keynr < keys.length(); keynr++)
{
if (keys & 1)
if (keys.is_set(keynr))
{
int new_error=remove_key(trans, keynr, record, prim_key);
if (new_error)
......@@ -1261,7 +1265,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. */
......
......@@ -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_full; }
bool has_transactions() { return 1;}
int open(const char *name, int mode, uint test_if_locked);
......
......@@ -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);
......
......@@ -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 &
......
......@@ -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,
......
......@@ -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;
......
......@@ -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; }
......
......@@ -801,11 +801,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.
*/
......@@ -834,8 +834,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 ==
......@@ -899,7 +899,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;
......@@ -908,14 +908,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;
......
......@@ -647,7 +647,6 @@ class Item_func_in :public Item_int_func
~Item_func_in() { delete array; delete in_item; }
optimize_type select_optimize() const
{ return array ? OPTIMIZE_KEY : OPTIMIZE_NONE; }
Item *key_item() const { return args[0]; }
void print(String *str);
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; }
......
......@@ -81,12 +81,12 @@ bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count)
}
bool Item_func::agg_arg_collations_for_comparison(DTCollation &c,
bool Item_func::agg_arg_collations_for_comparison(DTCollation &c,
Item **av, uint count)
{
if (agg_arg_collations(c, av, count))
return TRUE;
if (c.derivation == DERIVATION_NONE)
{
my_coll_agg_error(av, count, func_name());
......@@ -211,7 +211,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
item= *arg;
if (item->maybe_null)
maybe_null=1;
with_sum_func= with_sum_func || item->with_sum_func;
used_tables_cache|= item->used_tables();
not_null_tables_cache|= item->not_null_tables();
......@@ -2554,9 +2554,13 @@ void Item_func_match::init_search(bool no_order)
DBUG_VOID_RETURN;
if (key == NO_SUCH_KEY)
{
List<Item> fields;
for (uint i=1; i < arg_count; i++)
fields.push_back(args[i]);
concat=new Item_func_concat_ws(new Item_string(" ",1,
default_charset_info),
fields);
cmp_collation.collation), fields);
}
if (master)
{
......@@ -2568,14 +2572,19 @@ void Item_func_match::init_search(bool no_order)
}
String *ft_tmp= 0;
char tmp1[FT_QUERY_MAXLEN];
String tmp2(tmp1,sizeof(tmp1),default_charset_info);
// MATCH ... AGAINST (NULL) is meaningless, but possible
if (!(ft_tmp=key_item()->val_str(&tmp2)))
if (!(ft_tmp=key_item()->val_str(&value)))
{
ft_tmp= &tmp2;
tmp2.set("",0,default_charset_info);
ft_tmp= &value;
value.set("",0,cmp_collation.collation);
}
if (ft_tmp->charset() != cmp_collation.collation)
{
search_value.copy(ft_tmp->ptr(), ft_tmp->length(), ft_tmp->charset(),
cmp_collation.collation);
ft_tmp= &search_value;
}
ft_handler=table->file->ft_init_ext(mode, key,
......@@ -2592,7 +2601,6 @@ void Item_func_match::init_search(bool no_order)
bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
List_iterator<Item> li(fields);
Item *item;
maybe_null=1;
......@@ -2604,51 +2612,37 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
modifications to find_best and auto_close as complement to auto_init code
above.
*/
if (Item_func::fix_fields(thd, tlist, ref) || !const_item())
if (Item_func::fix_fields(thd, tlist, ref) || !args[0]->const_item())
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"AGAINST");
return 1;
}
while ((item=li++))
const_item_cache=0;
for (uint i=1 ; i < arg_count ; i++)
{
if (item->fix_fields(thd, tlist, li.ref()) || item->check_cols(1))
return 1;
item=args[i];
if (item->type() == Item::REF_ITEM)
li.replace(item= *((Item_ref *)item)->ref);
if (item->type() != Item::FIELD_ITEM || !item->used_tables())
args[i]= item= *((Item_ref *)item)->ref;
if (item->type() != Item::FIELD_ITEM)
key=NO_SUCH_KEY;
used_tables_cache|=item->used_tables();
}
/* check that all columns come from the same table */
if (my_count_bits(used_tables_cache) != 1)
key=NO_SUCH_KEY;
const_item_cache=0;
table=((Item_field *)fields.head())->field->table;
table->fulltext_searched=1;
record=table->record[0];
if (key == NO_SUCH_KEY && mode != FT_BOOL)
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH");
return 1;
}
return 0;
}
bool Item_func_match::walk(Item_processor processor, byte *arg)
{
List_iterator_fast<Item> li(fields);
Item *item;
while ((item= li++))
if (item->walk(processor, arg))
return 1;
return Item_func::walk(processor, arg);
table=((Item_field *)item)->field->table;
table->fulltext_searched=1;
return agg_arg_collations_for_comparison(cmp_collation, args+1, arg_count-1);
}
bool Item_func_match::fix_index()
{
List_iterator_fast<Item> li(fields);
Item_field *item;
uint ft_to_key[MAX_KEY], ft_cnt[MAX_KEY], fts=0, keynr;
uint max_cnt=0, mkeys=0;
......@@ -2659,7 +2653,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;
......@@ -2670,8 +2664,9 @@ bool Item_func_match::fix_index()
if (!fts)
goto err;
while ((item=(Item_field*)(li++)))
for (uint i=1; i < arg_count; i++)
{
item=(Item_field*)args[i];
for (keynr=0 ; keynr < fts ; keynr++)
{
KEY *ft_key=&table->key_info[ft_to_key[keynr]];
......@@ -2705,8 +2700,8 @@ bool Item_func_match::fix_index()
for (keynr=0 ; keynr <= mkeys ; keynr++)
{
// for now, partial keys won't work. SerG
if (max_cnt < fields.elements ||
// partial keys doesn't work
if (max_cnt < arg_count-1 ||
max_cnt < table->key_info[ft_to_key[keynr]].key_parts)
continue;
......@@ -2721,8 +2716,7 @@ err:
key=NO_SUCH_KEY;
return 0;
}
my_printf_error(ER_FT_MATCHING_KEY_NOT_FOUND,
ER(ER_FT_MATCHING_KEY_NOT_FOUND),MYF(0));
my_error(ER_FT_MATCHING_KEY_NOT_FOUND,MYF(0));
return 1;
}
......@@ -2768,7 +2762,8 @@ double Item_func_match::val()
(byte *)a->ptr(), a->length()));
}
else
DBUG_RETURN(ft_handler->please->find_relevance(ft_handler, record, 0));
DBUG_RETURN(ft_handler->please->find_relevance(ft_handler,
table->record[0], 0));
}
......
......@@ -962,20 +962,18 @@ public:
class Item_func_match :public Item_real_func
{
public:
List<Item> fields;
String value;
TABLE *table;
Item_func_match *master;
FT_INFO * ft_handler;
Item *concat;
byte *record;
uint key, mode;
bool join_key;
DTCollation cmp_collation;
FT_INFO *ft_handler;
TABLE *table;
Item_func_match *master; // for master-slave optimization
Item *concat; // Item_func_concat_ws
String value; // value of concat
String search_value; // key_item()'s value converted to cmp_collation
Item_func_match(List<Item> &a, Item *b): Item_real_func(b),
fields(a), table(0), master(0), ft_handler(0),
concat(0), key(0), join_key(0)
{}
Item_func_match(List<Item> &a): Item_real_func(a),
table(0), master(0), ft_handler(0), concat(0), key(0), join_key(0) { }
~Item_func_match()
{
if (!master && ft_handler)
......@@ -999,17 +997,13 @@ public:
bool fix_index();
void init_search(bool no_order);
bool walk(Item_processor processor, byte *arg);
};
class Item_func_match_nl :public Item_func_match
{
public:
Item_func_match_nl(List<Item> &a, Item *b)
:Item_func_match(a,b)
{ mode=FT_NL; }
Item_func_match_nl(List<Item> &a) :Item_func_match(a) { mode=FT_NL; }
const char *func_name() const { return "match_nl"; }
};
......@@ -1017,9 +1011,7 @@ public:
class Item_func_match_bool :public Item_func_match
{
public:
Item_func_match_bool(List<Item> &a, Item *b)
:Item_func_match(a,b)
{ mode=FT_BOOL; }
Item_func_match_bool(List<Item> &a) :Item_func_match(a) { mode=FT_BOOL; }
const char *func_name() const { return "match_bool"; }
};
......
......@@ -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>
{
ulonglong 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>
......@@ -647,8 +752,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);
......@@ -656,7 +761,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);
......
......@@ -2159,7 +2159,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
init_global_datetime_format(DATETIME_FORMAT_TYPE, 1))
return 1;
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;
}
......
......@@ -305,7 +305,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);
......@@ -364,7 +364,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);
}
......@@ -589,18 +588,18 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
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)
......@@ -616,8 +615,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
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;
......@@ -650,7 +649,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
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)
......@@ -666,7 +665,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
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;
......@@ -697,11 +696,11 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
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))
{
/*
......@@ -2128,7 +2127,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;
}
......@@ -2870,17 +2869,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))
......
......@@ -128,7 +128,7 @@ class SQL_SELECT :public Sql_alloc {
SQL_SELECT();
~SQL_SELECT();
bool check_quick(THD *thd, bool force_quick_range, ha_rows limit)
{ return test_quick_select(thd, ~0L,0,limit, force_quick_range) < 0; }
{ return test_quick_select(thd, key_map(~0L),0,limit, force_quick_range) < 0; }
inline bool skipp_record() { return cond ? cond->val_int() == 0 : 0; }
int test_quick_select(THD *thd, key_map keys, table_map prev_tables,
ha_rows limit, bool force_quick_range=0);
......
......@@ -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
......
......@@ -277,9 +277,10 @@ character-set=latin1
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format",
"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
"Incorrect index name '%-.100s'",
"Column '%-.64s' cannot be part of FULLTEXT index"
......@@ -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);
......
......@@ -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);
}
......
......@@ -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;
}
}
......
......@@ -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)
......
This diff is collapsed.
......@@ -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;
......
......@@ -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);
......
......@@ -424,7 +424,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
if (!sql_field->charset)
sql_field->charset= create_info->table_charset;
sql_field->create_length_to_internal_length();
/* Don't pack keys in old tables if the user has requested this */
if ((sql_field->flags & BLOB_FLAG) ||
sql_field->sql_type == FIELD_TYPE_VAR_STRING &&
......@@ -663,12 +663,11 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
key_info->usable_key_parts= key_number;
key_info->algorithm=key->algorithm;
/* TODO: Add proper checks if handler supports key_type and algorithm */
if (key->type == Key::FULLTEXT)
{
if (!(file->table_flags() & HA_CAN_FULLTEXT))
{
my_error(ER_TABLE_CANT_HANDLE_FULLTEXT, MYF(0));
my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0));
DBUG_RETURN(-1);
}
}
......@@ -680,6 +679,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
checking for proper key parts number:
*/
/* TODO: Add proper checks if handler supports key_type and algorithm */
if (key_info->flags == HA_SPATIAL)
{
if (key_info->key_parts != 1)
......@@ -704,6 +704,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
}
List_iterator<key_part_spec> cols(key->columns);
CHARSET_INFO *ft_key_charset=0; // for FULLTEXT
for (uint column_nr=0 ; (column=cols++) ; column_nr++)
{
it.rewind();
......@@ -727,64 +728,88 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
from a data prefix, ignoring column->length).
*/
if (key->type == Key::FULLTEXT)
{
if ((sql_field->sql_type != FIELD_TYPE_STRING &&
sql_field->sql_type != FIELD_TYPE_VAR_STRING &&
!f_is_blob(sql_field->pack_flag)) ||
sql_field->charset == &my_charset_bin ||
sql_field->charset->state & MY_CS_NONTEXT || // ucs2 doesn't work yet
(ft_key_charset && sql_field->charset != ft_key_charset))
{
my_printf_error(ER_BAD_FT_COLUMN,ER(ER_BAD_FT_COLUMN),MYF(0),
column->field_name);
DBUG_RETURN(-1);
}
ft_key_charset=sql_field->charset;
/*
for fulltext keys keyseg length is 1 for blobs (it's ignored in ft
code anyway, and 0 (set to column width later) for char's. it has
to be correct col width for char's, as char data are not prefixed
with length (unlike blobs, where ft code takes data length from a
data prefix, ignoring column->length).
*/
column->length=test(f_is_blob(sql_field->pack_flag));
}
else
{
column->length*= sql_field->charset->mbmaxlen;
if (f_is_blob(sql_field->pack_flag))
{
if (!(file->table_flags() & HA_BLOB_KEY))
{
my_printf_error(ER_BLOB_USED_AS_KEY,ER(ER_BLOB_USED_AS_KEY),MYF(0),
column->field_name);
DBUG_RETURN(-1);
}
if (!column->length)
{
my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH,
ER(ER_BLOB_KEY_WITHOUT_LENGTH),MYF(0),
column->field_name);
DBUG_RETURN(-1);
}
}
if (key->type == Key::SPATIAL)
{
if (!column->length )
{
/*
BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
Lately we'll extend this code to support more dimensions
*/
column->length=4*sizeof(double);
}
}
if (!(sql_field->flags & NOT_NULL_FLAG))
{
if (key->type == Key::PRIMARY)
{
/* Implicitly set primary key fields to NOT NULL for ISO conf. */
sql_field->flags|= NOT_NULL_FLAG;
sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
}
else
key_info->flags|= HA_NULL_PART_KEY;
if (!(file->table_flags() & HA_NULL_KEY))
{
my_printf_error(ER_NULL_COLUMN_IN_INDEX,ER(ER_NULL_COLUMN_IN_INDEX),
MYF(0),column->field_name);
DBUG_RETURN(-1);
}
if (key->type == Key::SPATIAL)
{
my_error(ER_SPATIAL_CANT_HAVE_NULL, MYF(0));
DBUG_RETURN(-1);
}
}
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
{
if (column_nr == 0 || (file->table_flags() & HA_AUTO_PART_KEY))
auto_increment--; // Field is used
if (f_is_blob(sql_field->pack_flag))
{
if (!(file->table_flags() & HA_BLOB_KEY))
{
my_printf_error(ER_BLOB_USED_AS_KEY,ER(ER_BLOB_USED_AS_KEY),MYF(0),
column->field_name);
DBUG_RETURN(-1);
}
if (!column->length)
{
my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH,
ER(ER_BLOB_KEY_WITHOUT_LENGTH),MYF(0),
column->field_name);
DBUG_RETURN(-1);
}
}
if (key->type == Key::SPATIAL)
{
if (!column->length )
{
/*
BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
Lately we'll extend this code to support more dimensions
*/
column->length=4*sizeof(double);
}
}
if (!(sql_field->flags & NOT_NULL_FLAG))
{
if (key->type == Key::PRIMARY)
{
/* Implicitly set primary key fields to NOT NULL for ISO conf. */
sql_field->flags|= NOT_NULL_FLAG;
sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
}
else
key_info->flags|= HA_NULL_PART_KEY;
if (!(file->table_flags() & HA_NULL_KEY))
{
my_printf_error(ER_NULL_COLUMN_IN_INDEX,ER(ER_NULL_COLUMN_IN_INDEX),
MYF(0),column->field_name);
DBUG_RETURN(-1);
}
if (key->type == Key::SPATIAL)
{
my_error(ER_SPATIAL_CANT_HAVE_NULL, MYF(0));
DBUG_RETURN(-1);
}
}
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
{
if (column_nr == 0 || (file->table_flags() & HA_AUTO_PART_KEY))
auto_increment--; // Field is used
}
}
key_part_info->fieldnr= field;
key_part_info->offset= (uint16) sql_field->offset;
key_part_info->key_type=sql_field->pack_flag;
......
......@@ -173,10 +173,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,
......
......@@ -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(thd, 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;
}
}
......
......@@ -2449,11 +2449,13 @@ simple_expr:
| singlerow_subselect { $$= $1; }
| '{' ident expr '}' { $$= $3; }
| MATCH ident_list_arg AGAINST '(' expr ')'
{ Select->add_ftfunc_to_list((Item_func_match *)
($$=new Item_func_match_nl(*$2,$5))); }
{ $2->push_front($5);
Select->add_ftfunc_to_list((Item_func_match *)
($$=new Item_func_match_nl(*$2))); }
| MATCH ident_list_arg AGAINST '(' expr IN_SYM BOOLEAN_SYM MODE_SYM ')'
{ Select->add_ftfunc_to_list((Item_func_match *)
($$=new Item_func_match_bool(*$2,$5))); }
{ $2->push_front($5);
Select->add_ftfunc_to_list((Item_func_match *)
($$=new Item_func_match_bool(*$2))); }
| ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); }
| BINARY expr %prec NEG
{
......@@ -2461,10 +2463,10 @@ simple_expr:
6, &my_charset_latin1));
}
| CAST_SYM '(' expr AS cast_type ')'
{
$$= create_func_cast($3, $5,
{
$$= create_func_cast($3, $5,
Lex->length ? atoi(Lex->length) : -1,
Lex->charset);
Lex->charset);
}
| CASE_SYM opt_expr WHEN_SYM when_list opt_else END
{ $$= new Item_func_case(* $4, $2, $5 ); }
......@@ -2967,7 +2969,7 @@ ident_list2:
opt_expr:
/* empty */ { $$= NULL; }
| expr { $$= $1; };
| expr { $$= $1; };
opt_else:
/* empty */ { $$= NULL; }
......
......@@ -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;
......@@ -155,10 +156,23 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0)));
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);
if (disk_buff[1] & 0x80)
{
outparam->keys= keys= uint2korr(disk_buff) & 0x7fff;
outparam->key_parts= key_parts= uint2korr(disk_buff+2);
}
else
{
outparam->keys= keys= disk_buff[0];
outparam->key_parts= key_parts= disk_buff[1];
}
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);
if (!(keyinfo = (KEY*) alloc_root(&outparam->mem_root,
n_length+uint2korr(disk_buff+4))))
......@@ -263,7 +277,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
record[outparam->reclength]=0; // For purify and ->c_ptr()
outparam->rec_buff_length=rec_buff_length;
if (my_pread(file,(byte*) record,(uint) outparam->reclength,
(ulong) (uint2korr(head+6)+uint2korr(head+14)),
(ulong) (uint2korr(head+6)+
((uint2korr(head+14) == 0xffff ?
uint4korr(head+10) : uint2korr(head+14)))),
MYF(MY_NABP)))
goto err_not_open; /* purecov: inspected */
/* HACK: table->record[2] is used instead of table->default_values here */
......@@ -484,8 +500,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 +561,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 +569,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 +616,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;
/*
......@@ -1108,6 +1124,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
key_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
length=(ulong) next_io_size((ulong) (IO_SIZE+key_length+reclength));
int4store(fileinfo+10,length);
if (key_length > 0xffff) key_length=0xffff;
int2store(fileinfo+14,key_length);
int2store(fileinfo+16,reclength);
int4store(fileinfo+18,create_info->max_rows);
......
......@@ -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);
......@@ -92,15 +92,15 @@ int rea_create_table(THD *thd, my_string file_name,
DBUG_RETURN(1);
}
uint key_buff_length=uint2korr(fileinfo+14);
keybuff=(uchar*) my_alloca(key_buff_length);
uint key_buff_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
keybuff=(uchar*) my_malloc(key_buff_length, MYF(0));
key_info_length=pack_keys(keybuff,keys,key_info);
VOID(get_form_pos(file,fileinfo,&formnames));
if (!(filepos=make_new_entry(file,fileinfo,&formnames,"")))
goto err;
maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000));
int2store(forminfo+2,maxlength);
int4store(fileinfo+10,(ulong) (filepos+maxlength));
int4store(fileinfo+10,key_buff_length);
fileinfo[26]= (uchar) test((create_info->max_rows == 1) &&
(create_info->min_rows == 1) && (keys == 0));
int2store(fileinfo+28,key_info_length);
......@@ -148,7 +148,7 @@ int rea_create_table(THD *thd, my_string file_name,
#endif
my_free((gptr) screen_buff,MYF(0));
my_afree((gptr) keybuff);
my_free((gptr) keybuff, MYF(0));
VOID(my_close(file,MYF(MY_WME)));
if (ha_create_table(file_name,create_info,0))
goto err2;
......@@ -156,7 +156,7 @@ int rea_create_table(THD *thd, my_string file_name,
err:
my_free((gptr) screen_buff,MYF(0));
my_afree((gptr) keybuff);
my_free((gptr) keybuff, MYF(0));
VOID(my_close(file,MYF(MY_WME)));
err2:
my_delete(file_name,MYF(0));
......@@ -291,10 +291,17 @@ static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo)
}
*(pos++)=0;
keybuff[0]=(uchar) key_count;
keybuff[1]=(uchar) key_parts;
length=(uint) (keyname_pos-keybuff);
int2store(keybuff+2,length);
if (key_count > 127 || key_parts > 127)
{
key_count|=0x8000;
int2store(keybuff,key_count);
int2store(keybuff+2,key_parts);
}
else
{
keybuff[0]=(uchar) key_count;
keybuff[1]=(uchar) key_parts;
}
length=(uint) (pos-keyname_pos);
int2store(keybuff+4,length);
DBUG_RETURN((uint) (pos-keybuff));
......
......@@ -118,6 +118,12 @@ static int my_strcasecmp_bin(CHARSET_INFO * cs __attribute__((unused)),
return strcmp(s,t);
}
int my_mbcharlen_8bit(CHARSET_INFO *cs __attribute__((unused)),
uint c __attribute__((unused)))
{
return 1;
}
static int my_mb_wc_bin(CHARSET_INFO *cs __attribute__((unused)),
my_wc_t *wc,
const unsigned char *str,
......@@ -264,12 +270,12 @@ static int my_strnxfrm_bin(CHARSET_INFO *cs __attribute__((unused)),
static
uint my_instr_bin(CHARSET_INFO *cs __attribute__((unused)),
const char *b, uint b_length,
const char *s, uint s_length,
my_match_t *match, uint nmatch)
const char *b, uint b_length,
const char *s, uint s_length,
my_match_t *match, uint nmatch)
{
register const uchar *str, *search, *end, *search_end;
if (s_length <= b_length)
{
if (!s_length)
......@@ -282,32 +288,32 @@ uint my_instr_bin(CHARSET_INFO *cs __attribute__((unused)),
}
return 1; /* Empty string is always found */
}
str= (const uchar*) b;
search= (const uchar*) s;
end= (const uchar*) b+b_length-s_length+1;
search_end= (const uchar*) s + s_length;
skipp:
while (str != end)
{
if ( (*str++) == (*search))
{
register const uchar *i,*j;
i= str;
i= str;
j= search+1;
while (j != search_end)
if ((*i++) != (*j++))
goto skipp;
if (nmatch > 0)
{
match[0].beg= 0;
match[0].end= str- (const uchar*)b-1;
match[0].mblen= match[0].end;
if (nmatch > 1)
{
match[1].beg= match[0].end;
......@@ -338,7 +344,7 @@ MY_COLLATION_HANDLER my_collation_8bit_bin_handler =
static MY_CHARSET_HANDLER my_charset_handler=
{
NULL, /* ismbchar */
NULL, /* mbcharlen */
my_mbcharlen_8bit, /* mbcharlen */
my_numchars_8bit,
my_charpos_8bit,
my_lengthsp_8bit,
......
......@@ -170,14 +170,14 @@ int my_wc_mb_latin1(CHARSET_INFO *cs __attribute__((unused)),
{
if (str >= end)
return MY_CS_TOOSMALL;
return ((wc < 256) && ((str[0]=uni_latin1[wc]) || (!wc))) ? 1 : MY_CS_ILUNI;
}
static MY_CHARSET_HANDLER my_charset_handler=
{
NULL,
NULL,
my_mbcharlen_8bit,
my_numchars_8bit,
my_charpos_8bit,
my_lengthsp_8bit,
......
......@@ -1093,7 +1093,7 @@ skipp:
MY_CHARSET_HANDLER my_charset_8bit_handler=
{
NULL, /* ismbchar */
NULL, /* mbcharlen */
my_mbcharlen_8bit, /* mbcharlen */
my_numchars_8bit,
my_charpos_8bit,
my_lengthsp_8bit,
......
......@@ -717,7 +717,7 @@ static MY_COLLATION_HANDLER my_collation_ci_handler =
static MY_CHARSET_HANDLER my_charset_handler=
{
NULL, /* ismbchar */
NULL, /* mbcharlen */
my_mbcharlen_8bit, /* mbcharlen */
my_numchars_8bit,
my_charpos_8bit,
my_lengthsp_8bit,
......
......@@ -1540,10 +1540,10 @@ static uchar ctype_utf8[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0
};
static uchar to_lower_utf8[] = {
......
......@@ -192,7 +192,7 @@ vio_should_retry(Vio * vio __attribute__((unused)))
int vio_close(Vio * vio)
{
int r;
int r=0;
DBUG_ENTER("vio_close");
#ifdef __WIN__
if (vio->type == VIO_TYPE_NAMEDPIPE)
......@@ -206,7 +206,6 @@ int vio_close(Vio * vio)
else if (vio->type != VIO_CLOSED)
#endif /* __WIN__ */
{
r=0;
if (shutdown(vio->sd,2))
r= -1;
if (closesocket(vio->sd))
......@@ -369,9 +368,9 @@ int vio_read_shared_memory(Vio * vio, gptr buf, int size)
remain_local = size;
current_postion=buf;
do
do
{
if (vio->shared_memory_remain == 0)
if (vio->shared_memory_remain == 0)
{
if (WaitForSingleObject(vio->event_server_wrote,vio->net->read_timeout*1000) != WAIT_OBJECT_0)
{
......@@ -384,9 +383,9 @@ int vio_read_shared_memory(Vio * vio, gptr buf, int size)
length = size;
if (vio->shared_memory_remain < length)
if (vio->shared_memory_remain < length)
length = vio->shared_memory_remain;
if (length > remain_local)
if (length > remain_local)
length = remain_local;
memcpy(current_postion,vio->shared_memory_pos,length);
......@@ -396,7 +395,7 @@ int vio_read_shared_memory(Vio * vio, gptr buf, int size)
current_postion+=length;
remain_local-=length;
if (!vio->shared_memory_remain)
if (!vio->shared_memory_remain)
if (!SetEvent(vio->event_client_read)) DBUG_RETURN(-1);
} while (remain_local);
length = size;
......@@ -419,11 +418,11 @@ int vio_write_shared_memory(Vio * vio, const gptr buf, int size)
remain = size;
current_postion = buf;
while (remain != 0)
while (remain != 0)
{
if (WaitForSingleObject(vio->event_server_read,vio->net->write_timeout*1000) != WAIT_OBJECT_0)
{
DBUG_RETURN(-1);
DBUG_RETURN(-1);
};
sz = remain > shared_memory_buffer_length ? shared_memory_buffer_length: remain;
......
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