mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 18:20:07 +01:00
Merge serg.mylan:/usr/home/serg/Abk/mysql-4.1-bug
into serg.mylan:/usr/home/serg/Abk/mysql-4.1
This commit is contained in:
commit
8cdc27da15
97 changed files with 1556 additions and 679 deletions
|
@ -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;
|
||||
|
|
|
@ -51,15 +51,18 @@ extern const char *ft_precompiled_stopwords[];
|
|||
|
||||
extern ulong ft_min_word_len;
|
||||
extern ulong ft_max_word_len;
|
||||
extern ulong ft_max_word_len_for_sort;
|
||||
extern ulong ft_query_expansion_limit;
|
||||
extern const char *ft_boolean_syntax;
|
||||
|
||||
int ft_init_stopwords(void);
|
||||
void ft_free_stopwords(void);
|
||||
|
||||
#define FT_NL 0
|
||||
#define FT_BOOL 1
|
||||
FT_INFO *ft_init_search(uint,void *, uint, byte *, uint, my_bool);
|
||||
#define FT_NL 0
|
||||
#define FT_BOOL 1
|
||||
#define FT_SORTED 2
|
||||
#define FT_EXPAND 4 /* query expansion */
|
||||
|
||||
FT_INFO *ft_init_search(uint,void *, uint, byte *, uint, byte *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -25,29 +25,36 @@ typedef struct st_bitmap
|
|||
{
|
||||
uchar *bitmap;
|
||||
uint bitmap_size;
|
||||
my_bool thread_safe; /* set if several threads access the bitmap */
|
||||
/*
|
||||
mutex will be acquired for the duration of each bitmap operation if
|
||||
thread_safe flag is set. Otherwise, we optimize by not acquiring the
|
||||
mutex
|
||||
thread_safe flag in bitmap_init was set. Otherwise, we optimize by not
|
||||
acquiring the mutex
|
||||
*/
|
||||
#ifdef THREAD
|
||||
pthread_mutex_t mutex;
|
||||
pthread_mutex_t *mutex;
|
||||
#endif
|
||||
} MY_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
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
#define FT_CORE
|
||||
#include "ftdefs.h"
|
||||
#include <queues.h>
|
||||
#include <assert.h> /* for DBUG_ASSERT() */
|
||||
|
||||
/* search with boolean queries */
|
||||
|
||||
|
@ -144,7 +142,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,¶m)))
|
||||
while ((res=ft_get_word(ftb->charset,start,end,&w,¶m)))
|
||||
{
|
||||
int r=param.plusminus;
|
||||
float weight= (float) (param.pmsign ? nwghts : wghts)[(r>5)?5:((r<-5)?-5:r)];
|
||||
|
@ -168,7 +166,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));
|
||||
|
@ -336,8 +338,7 @@ static void _ftb_init_index_search(FT_INFO *ftb)
|
|||
|
||||
|
||||
FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query,
|
||||
uint query_len,
|
||||
my_bool presort __attribute__((unused)))
|
||||
uint query_len)
|
||||
{
|
||||
FTB *ftb;
|
||||
FTB_EXPR *ftbe;
|
||||
|
@ -350,8 +351,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 +387,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 +605,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)
|
||||
|
|
|
@ -167,17 +167,28 @@ static int walk_and_copy(FT_SUPERDOC *from,
|
|||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
static int walk_and_push(FT_SUPERDOC *from,
|
||||
uint32 count __attribute__((unused)), QUEUE *best)
|
||||
{
|
||||
DBUG_ENTER("walk_and_copy");
|
||||
from->doc.weight+=from->tmp_weight*from->word_ptr->weight;
|
||||
set_if_smaller(best->elements, ft_query_expansion_limit-1)
|
||||
queue_insert(best, (byte *)& from->doc);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
static int FT_DOC_cmp(FT_DOC *a, FT_DOC *b)
|
||||
|
||||
static int FT_DOC_cmp(void *unused __attribute__((unused)),
|
||||
FT_DOC *a, FT_DOC *b)
|
||||
{
|
||||
return sgn(b->weight - a->weight);
|
||||
}
|
||||
|
||||
|
||||
FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query,
|
||||
uint query_len, my_bool presort)
|
||||
uint query_len, uint flags, byte *record)
|
||||
{
|
||||
TREE allocated_wtree, *wtree=&allocated_wtree;
|
||||
TREE wtree;
|
||||
ALL_IN_ONE aio;
|
||||
FT_DOC *dptr;
|
||||
FT_INFO *dlist=NULL;
|
||||
|
@ -196,24 +207,47 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query,
|
|||
aio.charset=info->s->keyinfo[keynr].seg->charset;
|
||||
aio.keybuff=info->lastkey+info->s->base.max_key_length;
|
||||
|
||||
bzero(&allocated_wtree,sizeof(allocated_wtree));
|
||||
bzero(&wtree,sizeof(wtree));
|
||||
|
||||
init_tree(&aio.dtree,0,0,sizeof(FT_SUPERDOC),(qsort_cmp2)&FT_SUPERDOC_cmp,0,
|
||||
NULL, NULL);
|
||||
|
||||
ft_parse_init(&allocated_wtree, aio.charset);
|
||||
if (ft_parse(&allocated_wtree,query,query_len))
|
||||
ft_parse_init(&wtree, aio.charset);
|
||||
if (ft_parse(&wtree,query,query_len,0))
|
||||
goto err;
|
||||
|
||||
if (tree_walk(wtree, (tree_walk_action)&walk_and_match, &aio,
|
||||
if (tree_walk(&wtree, (tree_walk_action)&walk_and_match, &aio,
|
||||
left_root_right))
|
||||
goto err2;
|
||||
goto err;
|
||||
|
||||
if (flags & FT_EXPAND && ft_query_expansion_limit)
|
||||
{
|
||||
QUEUE best;
|
||||
init_queue(&best,ft_query_expansion_limit,0,0, &FT_DOC_cmp, 0);
|
||||
tree_walk(&aio.dtree, (tree_walk_action) &walk_and_push,
|
||||
&best, left_root_right);
|
||||
while (best.elements)
|
||||
{
|
||||
my_off_t docid=((FT_DOC *)queue_remove(& best, 0))->dpos;
|
||||
if (!(*info->read_record)(info,docid,record))
|
||||
{
|
||||
info->update|= HA_STATE_AKTIV;
|
||||
_mi_ft_parse(&wtree, info, keynr, record,1);
|
||||
}
|
||||
}
|
||||
delete_queue(&best);
|
||||
reset_tree(&aio.dtree);
|
||||
if (tree_walk(&wtree, (tree_walk_action)&walk_and_match, &aio,
|
||||
left_root_right))
|
||||
goto err;
|
||||
|
||||
}
|
||||
|
||||
dlist=(FT_INFO *)my_malloc(sizeof(FT_INFO)+
|
||||
sizeof(FT_DOC)*(aio.dtree.elements_in_tree-1),
|
||||
MYF(0));
|
||||
if(!dlist)
|
||||
goto err2;
|
||||
if (!dlist)
|
||||
goto err;
|
||||
|
||||
dlist->please= (struct _ft_vft *) & _ft_vft_nlq;
|
||||
dlist->ndocs=aio.dtree.elements_in_tree;
|
||||
|
@ -224,14 +258,12 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query,
|
|||
tree_walk(&aio.dtree, (tree_walk_action) &walk_and_copy,
|
||||
&dptr, left_root_right);
|
||||
|
||||
if (presort)
|
||||
qsort(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort_cmp)&FT_DOC_cmp);
|
||||
|
||||
err2:
|
||||
delete_tree(wtree);
|
||||
delete_tree(&aio.dtree);
|
||||
if (flags & FT_SORTED)
|
||||
qsort2(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort2_cmp)&FT_DOC_cmp, 0);
|
||||
|
||||
err:
|
||||
delete_tree(&aio.dtree);
|
||||
delete_tree(&wtree);
|
||||
info->lastpos=saved_lastpos;
|
||||
DBUG_RETURN(dlist);
|
||||
}
|
||||
|
|
|
@ -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,32 +142,33 @@ 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;
|
||||
byte *doc= *start;
|
||||
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=0;
|
||||
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;
|
||||
*start= doc;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
|
@ -194,14 +183,23 @@ void ft_parse_init(TREE *wtree, CHARSET_INFO *cs)
|
|||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
int ft_parse(TREE *wtree, byte *doc, int doclen)
|
||||
int ft_parse(TREE *wtree, byte *doc, int doclen, my_bool with_alloc)
|
||||
{
|
||||
byte *end=doc+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 (with_alloc)
|
||||
{
|
||||
byte *ptr;
|
||||
/* allocating the data in the tree - to avoid mallocs and frees */
|
||||
DBUG_ASSERT(wtree->with_delete==0);
|
||||
ptr=(byte *)alloc_root(& wtree->mem_root,w.len);
|
||||
memcpy(ptr, w.pos, w.len);
|
||||
w.pos=ptr;
|
||||
}
|
||||
if (!tree_insert(wtree, &w, 0, wtree->custom_arg))
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
ulong ft_min_word_len=4;
|
||||
ulong ft_max_word_len=HA_FT_MAXLEN;
|
||||
ulong ft_max_word_len_for_sort=20;
|
||||
ulong ft_query_expansion_limit=5;
|
||||
const char *ft_boolean_syntax="+ -><()~*:\"\"&|";
|
||||
|
||||
const HA_KEYSEG ft_keysegs[FT_SEGS]={
|
||||
|
@ -53,14 +53,13 @@ const struct _ft_vft _ft_vft_boolean = {
|
|||
ft_boolean_get_relevance, ft_boolean_reinit_search
|
||||
};
|
||||
|
||||
FT_INFO *(*_ft_init_vft[2])(MI_INFO *, uint, byte *, uint, my_bool) =
|
||||
{ ft_init_nlq_search, ft_init_boolean_search };
|
||||
|
||||
FT_INFO *ft_init_search(uint mode, void *info, uint keynr,
|
||||
byte *query, uint query_len, my_bool presort)
|
||||
FT_INFO *ft_init_search(uint flags, void *info, uint keynr,
|
||||
byte *query, uint query_len, byte *record)
|
||||
{
|
||||
return (*_ft_init_vft[mode])((MI_INFO *)info, keynr,
|
||||
query, query_len, presort);
|
||||
if (flags & FT_BOOL)
|
||||
ft_init_boolean_search((MI_INFO *)info, keynr, query, query_len);
|
||||
else
|
||||
ft_init_nlq_search((MI_INFO *)info, keynr, query, query_len, flags, record);
|
||||
}
|
||||
|
||||
const char *ft_stopword_file = 0;
|
||||
|
|
|
@ -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;
|
||||
|
@ -106,7 +97,8 @@ uint _mi_ft_segiterator(register FT_SEG_ITERATOR *ftsi)
|
|||
|
||||
/* parses a document i.e. calls ft_parse for every keyseg */
|
||||
|
||||
uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record)
|
||||
uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr,
|
||||
const byte *record, my_bool with_alloc)
|
||||
{
|
||||
FT_SEG_ITERATOR ftsi;
|
||||
DBUG_ENTER("_mi_ft_parse");
|
||||
|
@ -117,21 +109,19 @@ uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record)
|
|||
while (_mi_ft_segiterator(&ftsi))
|
||||
{
|
||||
if (ftsi.pos)
|
||||
if (ft_parse(parsed, (byte *)ftsi.pos, ftsi.len))
|
||||
if (ft_parse(parsed, (byte *)ftsi.pos, ftsi.len, with_alloc))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
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");
|
||||
|
||||
bzero((char*) &ptree, sizeof(ptree));
|
||||
if (_mi_ft_parse(&ptree, info, keynr, record))
|
||||
if (_mi_ft_parse(&ptree, info, keynr, record,0))
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
DBUG_RETURN(ft_linearize(&ptree));
|
||||
|
@ -208,9 +198,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 +248,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 +267,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 +295,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));
|
||||
}
|
||||
|
||||
|
|
|
@ -73,14 +73,14 @@ for $file (split) {
|
|||
|
||||
for (0..$#l1) {
|
||||
$pp[$_]+=$p[$_]; $mm[$_]+=$m[$_];
|
||||
$total.=rep($file, ($#l1 ? $_ : undef), $p[$_], $m[$_]);
|
||||
$total[$_].=rep($file, ($#l1 ? $_ : undef), $p[$_], $m[$_]);
|
||||
}
|
||||
close OUT1;
|
||||
close OUT2;
|
||||
}
|
||||
|
||||
for (0..$#l1) {
|
||||
rep($total, ($#l1 ? $_ : undef), $pp[$_], $mm[$_]);
|
||||
rep($total[$_], ($#l1 ? $_ : undef), $pp[$_], $mm[$_]);
|
||||
}
|
||||
|
||||
sub rep {
|
||||
|
|
44
myisam/ftbench/Ecreate.pl
Executable file
44
myisam/ftbench/Ecreate.pl
Executable file
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
$test=shift || die "Usage $0 testname [option]";
|
||||
$option=shift;
|
||||
|
||||
open(D, "<data/$test.d") || die "Cannot open(<data/$test.d): $!";
|
||||
open(Q, "<data/$test.q") || die "Cannot open(<data/$test.q): $!";
|
||||
|
||||
$N=0;
|
||||
|
||||
print <<__HEADER__;
|
||||
DROP TABLE IF EXISTS $test;
|
||||
CREATE TABLE $test (
|
||||
id int(10) unsigned NOT NULL,
|
||||
text text NOT NULL,
|
||||
FULLTEXT KEY text (text)
|
||||
) TYPE=MyISAM CHARSET=latin1;
|
||||
|
||||
ALTER TABLE $test DISABLE KEYS;
|
||||
__HEADER__
|
||||
|
||||
while (<D>) { chomp;
|
||||
s/'/\\'/g; ++$N;
|
||||
print "INSERT $test VALUES ($N, '$_');\n";
|
||||
}
|
||||
|
||||
print <<__PREP__;
|
||||
ALTER TABLE $test ENABLE KEYS;
|
||||
SELECT $N;
|
||||
__PREP__
|
||||
|
||||
$N=0;
|
||||
|
||||
while (<Q>) { chomp;
|
||||
s/'/\\'/g; ++$N;
|
||||
$_="MATCH text AGAINST ('$_' $option)";
|
||||
print "SELECT $N, id, $_ FROM $test WHERE $_;\n";
|
||||
}
|
||||
|
||||
print <<__FOOTER__;
|
||||
DROP TABLE $test;
|
||||
__FOOTER__
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ sub Favg { my $a=shift; $Pavg*$Ravg ? 1/($a/$Pavg+(1-$a)/$Ravg) : 0; }
|
|||
# F0 : a=0 -- ignore precision
|
||||
# F5 : a=0.5
|
||||
# F1 : a=1 -- ignore recall
|
||||
while($eout_str =~ /^$qid\s+(\d+)\s+(\d+\.\d+)/) {
|
||||
while($eout_str =~ /^$qid\s+(\d+)\s+(\d+(?:\.\d+)?)/) {
|
||||
$B++;
|
||||
$AB++ if $dq{$1+0};
|
||||
$Ravg+=$AB;
|
||||
|
@ -41,11 +41,7 @@ sub Favg { my $a=shift; $Pavg*$Ravg ? 1/($a/$Pavg+(1-$a)/$Ravg) : 0; }
|
|||
$Ravg/=$B*$A if $B;
|
||||
$Pavg/=$B if $B;
|
||||
|
||||
write;
|
||||
format=
|
||||
@##### @#.#######
|
||||
$qid, Favg(0.5)
|
||||
.
|
||||
printf "%5d %1.12f %1.12f %1.12f\n", $qid, Favg(0),Favg(0.5),Favg(1);
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
|
43
myisam/ftbench/README
Normal file
43
myisam/ftbench/README
Normal file
|
@ -0,0 +1,43 @@
|
|||
1. should be run from myisam/ftbench/
|
||||
2. myisam/ftdefs.h should NOT be locked (bk get, not bk edit!)
|
||||
3. there should be ./data/ subdir with test collections, files:
|
||||
test1.d
|
||||
test1.q
|
||||
test1.r
|
||||
test2.d
|
||||
test2.q
|
||||
test2.r
|
||||
where test1, test2, etc - are arbitrary test names
|
||||
|
||||
*.[dq] files contain documents/queries one item per line.
|
||||
|
||||
*.r files have the structure:
|
||||
1 16 .....blablabla
|
||||
1 09 .....blablabla
|
||||
2 116 .....blablabla
|
||||
...
|
||||
|
||||
that is /^\d+\s+\d+/
|
||||
and are sorted by the first number (not necessarily by the second)
|
||||
|
||||
4. there should be ./t/ subdir with test directories
|
||||
|
||||
./t
|
||||
./t/BEST/
|
||||
./t/testdir1/
|
||||
./t/testdir2/
|
||||
...
|
||||
|
||||
there *must* be ./t/BEST/ subdir or a symlink to one of other dirs in ./t
|
||||
all other names (besides BEST) can be arbitrary
|
||||
|
||||
all test results are compared with BEST results.
|
||||
|
||||
test directories may contain ftdefs.h, my.cnf, ft_mode
|
||||
(the last one is used as in ... MATCH ... AGAINST ("..." $ft_mode) ...)
|
||||
NOTE: all *.out files in test directories will NOT be overwritten!
|
||||
delete them to re-test
|
||||
|
||||
5. run ./ft-test-run.sh
|
||||
6. go make some coffee
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/sh -x
|
||||
#!/bin/sh
|
||||
|
||||
if [ ! -x ./ft-test-run.sh ] ; then
|
||||
echo "Usage: ./ft-test-run.sh"
|
||||
|
@ -15,12 +15,7 @@ SOCK=$DATA/mysql.sock
|
|||
PID=$DATA/mysql.pid
|
||||
H=../ftdefs.h
|
||||
OPTS="--no-defaults --socket=$SOCK --character-sets-dir=$ROOT/sql/share/charsets"
|
||||
|
||||
# --ft_min_word_len=#
|
||||
# --ft_max_word_len=#
|
||||
# --ft_max_word_len_for_sort=#
|
||||
# --ft_stopword_file=name
|
||||
# --key_buffer_size=#
|
||||
DELAY=10
|
||||
|
||||
stop_myslqd()
|
||||
{
|
||||
|
@ -38,44 +33,66 @@ if [ -w $H ] ; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
for batch in t/BEST t/* ; do
|
||||
A=`ls $batch/*.out`
|
||||
[ ! -d $batch -o -n "$A" ] && continue
|
||||
stop_myslqd
|
||||
rm -rf var > /dev/null 2>&1
|
||||
mkdir var
|
||||
mkdir var/test
|
||||
|
||||
for batch in t/* ; do
|
||||
[ ! -d $batch ] && continue
|
||||
[ $batch -ef t/BEST -a $batch != t/BEST ] && continue
|
||||
|
||||
rm -rf var/test/* > /dev/null 2>&1
|
||||
rm -f $H
|
||||
ln -s $BASE/$batch/ftdefs.h $H
|
||||
touch $H
|
||||
if [ -f $BASE/$batch/ftdefs.h ] ; then
|
||||
cat $BASE/$batch/ftdefs.h > $H
|
||||
chmod a-wx $H
|
||||
else
|
||||
bk get -q $H
|
||||
fi
|
||||
OPTS="--defaults-file=$BASE/$batch/my.cnf --socket=$SOCK --character-sets-dir=$ROOT/sql/share/charsets"
|
||||
stop_myslqd
|
||||
rm $MYSQLD
|
||||
(cd $ROOT; gmake)
|
||||
rm -f $MYSQLD
|
||||
echo "building $batch"
|
||||
echo "============== $batch ===============" >> var/ft_test.log
|
||||
(cd $ROOT; gmake) >> var/ft_test.log 2>&1
|
||||
|
||||
for prog in $MYSQLD $MYSQL $MYSQLADMIN ; do
|
||||
if [ ! -x $prog ] ; then
|
||||
echo "No $prog"
|
||||
echo "build failed: no $prog"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
rm -rf var 2>&1 >/dev/null
|
||||
mkdir var
|
||||
mkdir var/test
|
||||
|
||||
echo "=====================================" >> var/ft_test.log
|
||||
$MYSQLD $OPTS --basedir=$BASE --skip-bdb --pid-file=$PID \
|
||||
--language=$ROOT/sql/share/english \
|
||||
--skip-grant-tables --skip-innodb \
|
||||
--skip-networking --tmpdir=$DATA &
|
||||
--skip-networking --tmpdir=$DATA >> var/ft_test.log 2>&1 &
|
||||
|
||||
$MYSQLADMIN $OPTS --connect_timeout=60 ping
|
||||
sleep $DELAY
|
||||
$MYSQLADMIN $OPTS ping
|
||||
if [ $? != 0 ] ; then
|
||||
echo "$MYSQLD refused to start"
|
||||
exit 1
|
||||
fi
|
||||
for test in `cd data; echo *.test|sed "s/\.test\>//g"` ; do
|
||||
$MYSQL $OPTS --skip-column-names test <data/$test.test >var/$test.eval
|
||||
./Ereport.pl var/$test.eval data/$test.relj > $batch/$test.out || exit
|
||||
for test in `cd data; echo *.r|sed "s/\.r//g"` ; do
|
||||
if [ -f $batch/$test.out ] ; then
|
||||
echo "skipping $batch/$test.out"
|
||||
continue
|
||||
fi
|
||||
echo "testing $batch/$test"
|
||||
FT_MODE=`cat $batch/ft_mode 2>/dev/null`
|
||||
./Ecreate.pl $test "$FT_MODE" | $MYSQL $OPTS --skip-column-names test >var/$test.eval
|
||||
echo "reporting $batch/$test"
|
||||
./Ereport.pl var/$test.eval data/$test.r > $batch/$test.out || exit
|
||||
done
|
||||
stop_myslqd
|
||||
rm -f $H
|
||||
[ $batch -ef t/BEST ] || ./Ecompare.pl t/BEST $batch >> t/BEST/report.txt
|
||||
bk get -q $H
|
||||
if [ ! $batch -ef t/BEST ] ; then
|
||||
echo "comparing $batch"
|
||||
./Ecompare.pl t/BEST $batch >> t/BEST/report.txt
|
||||
fi
|
||||
done
|
||||
|
||||
|
|
|
@ -21,9 +21,14 @@
|
|||
#include "fulltext.h"
|
||||
#include <m_ctype.h>
|
||||
#include <my_tree.h>
|
||||
#include <queues.h>
|
||||
#include <assert.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 FT_MAX_WORD_LEN_FOR_SORT 20
|
||||
|
||||
#define COMPILE_STOPWORDS_IN
|
||||
|
||||
|
@ -107,8 +112,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;
|
||||
|
@ -121,13 +126,15 @@ void _mi_ft_segiterator_dummy_init(const byte *, uint, FT_SEG_ITERATOR *);
|
|||
uint _mi_ft_segiterator(FT_SEG_ITERATOR *);
|
||||
|
||||
void ft_parse_init(TREE *, CHARSET_INFO *);
|
||||
int ft_parse(TREE *, byte *, int);
|
||||
int ft_parse(TREE *, byte *, int, my_bool);
|
||||
FT_WORD * ft_linearize(TREE *);
|
||||
FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, byte *, const byte *);
|
||||
uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record);
|
||||
FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, const byte *);
|
||||
uint _mi_ft_parse(TREE *, MI_INFO *, uint, const byte *, my_bool);
|
||||
|
||||
FT_INFO *ft_init_nlq_search(MI_INFO *, uint, byte *, uint, uint, byte *);
|
||||
FT_INFO *ft_init_boolean_search(MI_INFO *, uint, byte *, uint);
|
||||
|
||||
extern const struct _ft_vft _ft_vft_nlq;
|
||||
FT_INFO *ft_init_nlq_search(MI_INFO *, uint, byte *, uint, my_bool);
|
||||
int ft_nlq_read_next(FT_INFO *, char *);
|
||||
float ft_nlq_find_relevance(FT_INFO *, byte *, uint);
|
||||
void ft_nlq_close_search(FT_INFO *);
|
||||
|
@ -136,10 +143,10 @@ my_off_t ft_nlq_get_docid(FT_INFO *);
|
|||
void ft_nlq_reinit_search(FT_INFO *);
|
||||
|
||||
extern const struct _ft_vft _ft_vft_boolean;
|
||||
FT_INFO *ft_init_boolean_search(MI_INFO *, uint, byte *, uint, my_bool);
|
||||
int ft_boolean_read_next(FT_INFO *, char *);
|
||||
float ft_boolean_find_relevance(FT_INFO *, byte *, uint);
|
||||
void ft_boolean_close_search(FT_INFO *);
|
||||
float ft_boolean_get_relevance(FT_INFO *);
|
||||
my_off_t ft_boolean_get_docid(FT_INFO *);
|
||||
void ft_boolean_reinit_search(FT_INFO *);
|
||||
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <m_ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <my_getopt.h>
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_SYS_VADVISE_H
|
||||
#include <sys/vadvise.h>
|
||||
#endif
|
||||
|
@ -1955,11 +1954,11 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
|
|||
if (sort_param.keyinfo->flag & HA_FULLTEXT)
|
||||
{
|
||||
sort_info.max_records=
|
||||
(ha_rows) (sort_info.filelength/ft_max_word_len_for_sort+1);
|
||||
(ha_rows) (sort_info.filelength/FT_MAX_WORD_LEN_FOR_SORT+1);
|
||||
|
||||
sort_param.key_read=sort_ft_key_read;
|
||||
sort_param.key_write=sort_ft_key_write;
|
||||
sort_param.key_length+=ft_max_word_len_for_sort-HA_FT_MAXLEN;
|
||||
sort_param.key_length+=FT_MAX_WORD_LEN_FOR_SORT-HA_FT_MAXLEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2350,7 +2349,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
|
|||
total_key_length+=sort_param[i].key_length;
|
||||
|
||||
if (sort_param[i].keyinfo->flag & HA_FULLTEXT)
|
||||
sort_param[i].key_length+=ft_max_word_len_for_sort-ft_max_word_len;
|
||||
sort_param[i].key_length+=FT_MAX_WORD_LEN_FOR_SORT-ft_max_word_len;
|
||||
}
|
||||
sort_info.total_keys=i;
|
||||
sort_param[0].master= 1;
|
||||
|
@ -2575,8 +2574,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;
|
||||
|
@ -3876,7 +3874,7 @@ static my_bool mi_too_big_key_for_sort(MI_KEYDEF *key, ha_rows rows)
|
|||
{
|
||||
uint key_maxlength=key->maxlength;
|
||||
if (key->flag & HA_FULLTEXT)
|
||||
key_maxlength+=ft_max_word_len_for_sort-HA_FT_MAXLEN;
|
||||
key_maxlength+=FT_MAX_WORD_LEN_FOR_SORT-HA_FT_MAXLEN;
|
||||
return (key->flag & (HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY | HA_FULLTEXT) &&
|
||||
((ulonglong) rows * key_maxlength >
|
||||
(ulonglong) myisam_max_temp_length));
|
||||
|
@ -3892,7 +3890,7 @@ void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows)
|
|||
MI_KEYDEF *key=share->keyinfo;
|
||||
for (i=0 ; i < share->base.keys ; i++,key++)
|
||||
{
|
||||
if (!(key->flag & (HA_NOSAME | HA_SPATIAL | HA_AUTO_KEY)) &&
|
||||
if (!(key->flag & (HA_NOSAME | HA_SPATIAL | HA_AUTO_KEY)) &&
|
||||
! mi_too_big_key_for_sort(key,rows) && info->s->base.auto_key != i+1)
|
||||
{
|
||||
share->state.key_map&= ~ ((ulonglong) 1 << i);
|
||||
|
|
|
@ -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((gptr)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)
|
||||
DBUG_RETURN(0); /* There is room on page */
|
||||
{
|
||||
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;
|
||||
|
|
|
@ -314,9 +314,6 @@ static struct my_option my_long_options[] =
|
|||
{ "ft_max_word_len", OPT_FT_MAX_WORD_LEN, "", (gptr*) &ft_max_word_len,
|
||||
(gptr*) &ft_max_word_len, 0, GET_ULONG, REQUIRED_ARG, HA_FT_MAXLEN, 10,
|
||||
HA_FT_MAXLEN, 0, 1, 0},
|
||||
{ "ft_max_word_len_for_sort", OPT_FT_MAX_WORD_LEN_FOR_SORT, "",
|
||||
(gptr*) &ft_max_word_len_for_sort, (gptr*) &ft_max_word_len_for_sort, 0,
|
||||
GET_ULONG, REQUIRED_ARG, 20, 4, HA_FT_MAXLEN, 0, 1, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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,
|
||||
|
|
|
@ -18,11 +18,20 @@ Full-text indexes are called collections
|
|||
Only MyISAM tables support collections
|
||||
select * from t1 where MATCH(a,b) AGAINST ("only");
|
||||
a b
|
||||
select * from t1 where MATCH(a,b) AGAINST ("collections") UNION ALL select * from t1 where MATCH(a,b) AGAINST ("indexes");
|
||||
select * from t1 where MATCH(a,b) AGAINST ("collections" WITH QUERY EXPANSION);
|
||||
a b
|
||||
Only MyISAM tables support collections
|
||||
Full-text indexes are called collections
|
||||
MySQL has now support for full-text search
|
||||
select * from t1 where MATCH(a,b) AGAINST ("indexes" WITH QUERY EXPANSION);
|
||||
a b
|
||||
Full-text indexes are called collections
|
||||
Only MyISAM tables support collections
|
||||
select * from t1 where MATCH(a,b) AGAINST ("indexes collections" WITH QUERY EXPANSION);
|
||||
a b
|
||||
Full-text indexes are called collections
|
||||
Only MyISAM tables support collections
|
||||
MySQL has now support for full-text search
|
||||
explain select * from t1 where MATCH(a,b) AGAINST ("collections");
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 fulltext a a 0 1 Using where
|
||||
|
@ -119,7 +128,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 +200,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 +288,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 Osnabrück');
|
||||
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 ('Osnabrück');
|
||||
t charset(t)
|
||||
SET NAMES latin1;
|
||||
SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('Osnabrück');
|
||||
t charset(t)
|
||||
aus Osnabrück 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;
|
||||
|
|
|
@ -3,5 +3,5 @@ Variable_name Value
|
|||
ft_boolean_syntax + -><()~*:""&|
|
||||
ft_min_word_len 4
|
||||
ft_max_word_len 254
|
||||
ft_max_word_len_for_sort 20
|
||||
ft_query_expansion_limit 20
|
||||
ft_stopword_file (built-in)
|
||||
|
|
|
@ -240,11 +240,11 @@ id select_type table type possible_keys key key_len ref rows Extra
|
|||
explain select * from t1, t1 t2 where t1.y = 2 and t2.x between t1.y-1 and t1.y+1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref y y 5 const 1 Using where
|
||||
1 SIMPLE t2 ALL x NULL NULL NULL 9 Range checked for each record (index map: 1)
|
||||
1 SIMPLE t2 ALL x NULL NULL NULL 9 Range checked for each record (index map: 0x1)
|
||||
explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= t1.y-1 and t2.x <= t1.y+1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref y y 5 const 1 Using where
|
||||
1 SIMPLE t2 ALL x NULL NULL NULL 9 Range checked for each record (index map: 1)
|
||||
1 SIMPLE t2 ALL x NULL NULL NULL 9 Range checked for each record (index map: 0x1)
|
||||
explain select * from t1, t1 t2 where t1.y = 2 and t2.x between 0 and t1.y;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref y y 5 const 1 Using where
|
||||
|
@ -267,11 +267,11 @@ INSERT INTO t2 VALUES (0),(0),(1),(1),(2),(2);
|
|||
explain select * from t1, t2 where (t1.key1 <t2.keya + 1) and t2.keya=3;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ref j1 j1 4 const 1 Using where; Using index
|
||||
1 SIMPLE t1 ALL i1,i2 NULL NULL NULL 4 Range checked for each record (index map: 3)
|
||||
1 SIMPLE t1 ALL i1,i2 NULL NULL NULL 4 Range checked for each record (index map: 0x3)
|
||||
explain select * from t1 force index(i2), t2 where (t1.key1 <t2.keya + 1) and t2.keya=3;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ref j1 j1 4 const 1 Using where; Using index
|
||||
1 SIMPLE t1 ALL i2 NULL NULL NULL 4 Range checked for each record (index map: 2)
|
||||
1 SIMPLE t1 ALL i2 NULL NULL NULL 4 Range checked for each record (index map: 0x2)
|
||||
DROP TABLE t1,t2;
|
||||
create table t1 (id int(10) primary key);
|
||||
insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
|
|
|
@ -20,9 +20,11 @@ select * from t1 where MATCH(a,b) AGAINST ("indexes");
|
|||
select * from t1 where MATCH(a,b) AGAINST ("indexes collections");
|
||||
select * from t1 where MATCH(a,b) AGAINST ("only");
|
||||
|
||||
# UNION of fulltext's
|
||||
select * from t1 where MATCH(a,b) AGAINST ("collections") UNION ALL select * from t1 where MATCH(a,b) AGAINST ("indexes");
|
||||
# query expansion
|
||||
|
||||
select * from t1 where MATCH(a,b) AGAINST ("collections" WITH QUERY EXPANSION);
|
||||
select * from t1 where MATCH(a,b) AGAINST ("indexes" WITH QUERY EXPANSION);
|
||||
select * from t1 where MATCH(a,b) AGAINST ("indexes collections" WITH QUERY EXPANSION);
|
||||
|
||||
# add_ft_keys() tests
|
||||
|
||||
|
@ -58,6 +60,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:
|
||||
|
||||
|
@ -65,7 +68,6 @@ select * from t1 where MATCH a AGAINST ("search" IN BOOLEAN MODE);
|
|||
select * from t1 where MATCH b AGAINST ("sear*" IN BOOLEAN MODE);
|
||||
|
||||
# UNION of fulltext's
|
||||
|
||||
select * from t1 where MATCH(a,b) AGAINST ("collections") UNION ALL select * from t1 where MATCH(a,b) AGAINST ("indexes");
|
||||
|
||||
#update/delete with fulltext index
|
||||
|
@ -129,6 +131,13 @@ select * from t2 having MATCH inhalt AGAINST ('foobar');
|
|||
# check of fulltext errors
|
||||
#
|
||||
|
||||
--error 1280
|
||||
CREATE TABLE t3 (t int(11),i text,fulltext tix (t,i));
|
||||
--error 1280
|
||||
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 +227,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 Osnabrück');
|
||||
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 ('Osnabrück');
|
||||
SET NAMES latin1;
|
||||
SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('Osnabrück');
|
||||
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,67 +27,73 @@
|
|||
#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)
|
||||
pthread_mutex_lock(&map->mutex);
|
||||
if (map->mutex)
|
||||
pthread_mutex_lock(map->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void bitmap_unlock(MY_BITMAP* map)
|
||||
inline void bitmap_unlock(MY_BITMAP *map)
|
||||
{
|
||||
#ifdef THREAD
|
||||
if (map->thread_safe)
|
||||
pthread_mutex_unlock(&map->mutex);
|
||||
if (map->mutex)
|
||||
pthread_mutex_unlock(map->mutex);
|
||||
#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,
|
||||
MYF(MY_WME | MY_ZEROFILL))))
|
||||
// for efficiency reasons - MY_BITMAP is heavily used
|
||||
DBUG_ASSERT((bitmap_size & 7) == 0);
|
||||
bitmap_size/=8;
|
||||
if (!(map->bitmap=buf) &&
|
||||
!(map->bitmap=(uchar*)my_malloc(bitmap_size + sizeof(pthread_mutex_t),
|
||||
MYF(MY_WME | MY_ZEROFILL))))
|
||||
return 1;
|
||||
DBUG_ASSERT(bitmap_size != ~(uint) 0);
|
||||
#ifdef THREAD
|
||||
if ((map->thread_safe = thread_safe))
|
||||
pthread_mutex_init(&map->mutex, MY_MUTEX_INIT_FAST);
|
||||
#endif
|
||||
map->bitmap_size=bitmap_size;
|
||||
#ifdef THREAD
|
||||
if (thread_safe)
|
||||
{
|
||||
map->mutex=(pthread_mutex_t *)(map->bitmap+bitmap_size);
|
||||
pthread_mutex_init(map->mutex, MY_MUTEX_INIT_FAST);
|
||||
}
|
||||
else
|
||||
map->mutex=0;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bitmap_free(MY_BITMAP *map)
|
||||
{
|
||||
#ifdef THREAD
|
||||
if (map->mutex)
|
||||
pthread_mutex_destroy(map->mutex);
|
||||
#endif
|
||||
if (map->bitmap)
|
||||
{
|
||||
my_free((char*) map->bitmap, MYF(0));
|
||||
map->bitmap=0;
|
||||
#ifdef THREAD
|
||||
if (map->thread_safe)
|
||||
pthread_mutex_destroy(&map->mutex);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit)
|
||||
{
|
||||
if (bitmap_bit < map->bitmap_size)
|
||||
{
|
||||
bitmap_lock(map);
|
||||
map->bitmap[bitmap_bit / 8] |= (1 << (bitmap_bit & 7));
|
||||
bitmap_unlock(map);
|
||||
}
|
||||
DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
|
||||
bitmap_lock(map);
|
||||
map->bitmap[bitmap_bit / 8] |= (1 << (bitmap_bit & 7));
|
||||
bitmap_unlock(map);
|
||||
}
|
||||
|
||||
|
||||
uint bitmap_set_next(MY_BITMAP *map)
|
||||
{
|
||||
uchar *bitmap=map->bitmap;
|
||||
uint bit_found = MY_BIT_NONE;
|
||||
uint bitmap_size=map->bitmap_size;
|
||||
uint bitmap_size=map->bitmap_size*8;
|
||||
uint i;
|
||||
|
||||
DBUG_ASSERT(map->bitmap);
|
||||
bitmap_lock(map);
|
||||
for (i=0; i < bitmap_size ; i++, bitmap++)
|
||||
{
|
||||
|
@ -110,35 +116,172 @@ uint bitmap_set_next(MY_BITMAP *map)
|
|||
return bit_found;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit)
|
||||
{
|
||||
if (bitmap_bit < map->bitmap_size)
|
||||
{
|
||||
bitmap_lock(map);
|
||||
map->bitmap[bitmap_bit / 8] &= ~ (1 << (bitmap_bit & 7));
|
||||
bitmap_unlock(map);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bitmap_set_all(MY_BITMAP* map)
|
||||
{
|
||||
DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
|
||||
bitmap_lock(map);
|
||||
memset(map->bitmap, 0xff, (map->bitmap_size+7)/8);
|
||||
map->bitmap[bitmap_bit / 8] &= ~ (1 << (bitmap_bit & 7));
|
||||
bitmap_unlock(map);
|
||||
}
|
||||
|
||||
my_bool bitmap_is_set(MY_BITMAP* map, uint bitmap_bit)
|
||||
void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
|
||||
{
|
||||
return (bitmap_bit < map->bitmap_size) ?
|
||||
(map->bitmap[bitmap_bit / 8] & (1 << (bitmap_bit & 7))) :
|
||||
0;
|
||||
}
|
||||
uint prefix_bytes, prefix_bits;
|
||||
|
||||
void bitmap_clear_all(MY_BITMAP* map)
|
||||
{
|
||||
DBUG_ASSERT(map->bitmap);
|
||||
bitmap_lock(map);
|
||||
bzero(map->bitmap,(map->bitmap_size+7)/8);
|
||||
set_if_smaller(prefix_size, map->bitmap_size*8);
|
||||
if ((prefix_bytes= prefix_size / 8))
|
||||
memset(map->bitmap, 0xff, prefix_bytes);
|
||||
if ((prefix_bits= prefix_size & 7))
|
||||
map->bitmap[prefix_bytes++]= (1 << prefix_bits)-1;
|
||||
if (prefix_bytes < map->bitmap_size)
|
||||
bzero(map->bitmap+prefix_bytes, map->bitmap_size-prefix_bytes);
|
||||
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, ~0);
|
||||
}
|
||||
|
||||
my_bool bitmap_is_prefix(MY_BITMAP *map, uint prefix_size)
|
||||
{
|
||||
uint prefix_bits= prefix_size & 7, res= 0;
|
||||
uchar *m= map->bitmap, *end_prefix= map->bitmap+prefix_size/8,
|
||||
*end= map->bitmap+map->bitmap_size;
|
||||
|
||||
DBUG_ASSERT(map->bitmap && prefix_size <= map->bitmap_size*8);
|
||||
|
||||
bitmap_lock(map);
|
||||
while (m < end_prefix)
|
||||
if (*m++ != 0xff)
|
||||
goto ret;
|
||||
|
||||
if (prefix_bits && *m++ != (1 << prefix_bits)-1)
|
||||
goto ret;
|
||||
|
||||
while (m < end)
|
||||
if (m++ != 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*8);
|
||||
}
|
||||
|
||||
my_bool bitmap_is_set(MY_BITMAP *map, uint bitmap_bit)
|
||||
{
|
||||
DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
|
||||
return map->bitmap[bitmap_bit / 8] & (1 << (bitmap_bit & 7));
|
||||
}
|
||||
|
||||
my_bool bitmap_is_subset(MY_BITMAP *map1, MY_BITMAP *map2)
|
||||
{
|
||||
uint length, res=0;
|
||||
uchar *m1=map1->bitmap, *m2=map2->bitmap, *end;
|
||||
|
||||
DBUG_ASSERT(map1->bitmap && map2->bitmap &&
|
||||
map1->bitmap_size==map2->bitmap_size);
|
||||
bitmap_lock(map1);
|
||||
bitmap_lock(map2);
|
||||
|
||||
end= m1+map1->bitmap_size;
|
||||
|
||||
while (m1 < end)
|
||||
if ((*m1++) & ~(*m2++))
|
||||
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 && map2->bitmap &&
|
||||
map1->bitmap_size==map2->bitmap_size);
|
||||
bitmap_lock(map1);
|
||||
bitmap_lock(map2);
|
||||
|
||||
res= memcmp(map1->bitmap, map2->bitmap, map1->bitmap_size)==0;
|
||||
|
||||
bitmap_unlock(map2);
|
||||
bitmap_unlock(map1);
|
||||
return res;
|
||||
}
|
||||
|
||||
void bitmap_intersect(MY_BITMAP *map, MY_BITMAP *map2)
|
||||
{
|
||||
uchar *to=map->bitmap, *from=map2->bitmap, *end;
|
||||
|
||||
DBUG_ASSERT(map->bitmap && map2->bitmap &&
|
||||
map->bitmap_size==map2->bitmap_size);
|
||||
bitmap_lock(map);
|
||||
bitmap_lock(map2);
|
||||
|
||||
end= to+map->bitmap_size;
|
||||
|
||||
while (to < end)
|
||||
*to++ &= *from++;
|
||||
|
||||
bitmap_unlock(map2);
|
||||
bitmap_unlock(map);
|
||||
}
|
||||
|
||||
void bitmap_subtract(MY_BITMAP *map, MY_BITMAP *map2)
|
||||
{
|
||||
uchar *to=map->bitmap, *from=map2->bitmap, *end;
|
||||
|
||||
DBUG_ASSERT(map->bitmap && map2->bitmap &&
|
||||
map->bitmap_size==map2->bitmap_size);
|
||||
bitmap_lock(map);
|
||||
bitmap_lock(map2);
|
||||
|
||||
end= to+map->bitmap_size;
|
||||
|
||||
while (to < end)
|
||||
*to++ &= ~(*from++);
|
||||
|
||||
bitmap_unlock(map2);
|
||||
bitmap_unlock(map);
|
||||
}
|
||||
|
||||
void bitmap_union(MY_BITMAP *map, MY_BITMAP *map2)
|
||||
{
|
||||
uchar *to=map->bitmap, *from=map2->bitmap, *end;
|
||||
|
||||
DBUG_ASSERT(map->bitmap && map2->bitmap &&
|
||||
map->bitmap_size==map2->bitmap_size);
|
||||
bitmap_lock(map);
|
||||
bitmap_lock(map2);
|
||||
|
||||
end= to+map->bitmap_size;
|
||||
|
||||
while (to < end)
|
||||
*to++ |= *from++;
|
||||
|
||||
bitmap_unlock(map2);
|
||||
bitmap_unlock(map);
|
||||
}
|
||||
|
||||
|
|
|
@ -181,7 +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),
|
||||
query_id(0), key_start(0), part_of_key(0), part_of_sortkey(0),
|
||||
unireg_check(unireg_check_arg),
|
||||
field_length(length_arg),null_bit(null_bit_arg),abs_offset(0)
|
||||
{
|
||||
|
|
|
@ -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(0);
|
||||
tmp->part_of_key.init(0);
|
||||
tmp->part_of_sortkey.init(0);
|
||||
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,10 @@ 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);
|
||||
table->keys_in_use.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,
|
||||
|
|
|
@ -89,9 +89,8 @@ class ha_myisam: public handler
|
|||
ft_handler->please->reinit_search(ft_handler);
|
||||
return 0;
|
||||
}
|
||||
FT_INFO *ft_init_ext(uint mode, uint inx,const byte *key, uint keylen,
|
||||
bool presort)
|
||||
{ return ft_init_search(mode, file,inx,(byte*) key,keylen,presort); }
|
||||
FT_INFO *ft_init_ext(uint flags, uint inx,const byte *key, uint keylen)
|
||||
{ return ft_init_search(flags,file,inx,(byte*) key,keylen, table->record[0]); }
|
||||
int ft_read(byte *buf);
|
||||
int rnd_init(bool scan=1);
|
||||
int rnd_next(byte *buf);
|
||||
|
|
|
@ -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; }
|
||||
|
@ -271,8 +271,7 @@ public:
|
|||
}
|
||||
virtual int ft_init()
|
||||
{ return -1; }
|
||||
virtual FT_INFO *ft_init_ext(uint mode,uint inx,const byte *key, uint keylen,
|
||||
bool presort)
|
||||
virtual FT_INFO *ft_init_ext(uint flags,uint inx,const byte *key, uint keylen)
|
||||
{ return NULL; }
|
||||
virtual int ft_read(byte *buf) { return -1; }
|
||||
virtual int rnd_init(bool scan=1)=0;
|
||||
|
|
20
sql/item.cc
20
sql/item.cc
|
@ -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.
|
||||
*/
|
||||
|
@ -842,8 +842,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
|||
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)
|
||||
{
|
||||
if (*refer && (*refer)->fixed) // Avoid crash in case of error
|
||||
|
@ -920,7 +920,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;
|
||||
|
@ -929,14 +929,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();
|
||||
|
@ -2603,9 +2603,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)
|
||||
{
|
||||
|
@ -2617,20 +2621,25 @@ 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);
|
||||
}
|
||||
|
||||
ft_handler=table->file->ft_init_ext(mode, key,
|
||||
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;
|
||||
}
|
||||
|
||||
if (join_key && !no_order) flags|=FT_SORTED;
|
||||
ft_handler=table->file->ft_init_ext(flags, key,
|
||||
(byte*) ft_tmp->ptr(),
|
||||
ft_tmp->length(),
|
||||
join_key && !no_order);
|
||||
ft_tmp->length());
|
||||
|
||||
if (join_key)
|
||||
table->file->ft_handler=ft_handler;
|
||||
|
@ -2641,7 +2650,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;
|
||||
|
@ -2653,51 +2661,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)
|
||||
if (key == NO_SUCH_KEY && !(flags & 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;
|
||||
|
@ -2708,7 +2702,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;
|
||||
|
@ -2719,8 +2713,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]];
|
||||
|
@ -2754,8 +2749,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;
|
||||
|
||||
|
@ -2765,21 +2760,20 @@ bool Item_func_match::fix_index()
|
|||
}
|
||||
|
||||
err:
|
||||
if (mode == FT_BOOL)
|
||||
if (flags & FT_BOOL)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
bool Item_func_match::eq(const Item *item, bool binary_cmp) const
|
||||
{
|
||||
if (item->type() != FUNC_ITEM ||
|
||||
func_name() != ((Item_func*)item)->func_name())
|
||||
if (item->type() != FUNC_ITEM || ((Item_func*)item)->functype() != FT_FUNC ||
|
||||
flags != ((Item_func_match*)item)->flags)
|
||||
return 0;
|
||||
|
||||
Item_func_match *ifm=(Item_func_match*) item;
|
||||
|
@ -2817,7 +2811,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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -971,20 +971,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;
|
||||
uint key, flags;
|
||||
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, uint b): Item_real_func(a), flags(b),
|
||||
table(0), master(0), ft_handler(0), concat(0), key(0), join_key(0) { }
|
||||
~Item_func_match()
|
||||
{
|
||||
if (!master && ft_handler)
|
||||
|
@ -999,6 +997,7 @@ public:
|
|||
delete concat;
|
||||
}
|
||||
enum Functype functype() const { return FT_FUNC; }
|
||||
const char *func_name() const { return "match"; }
|
||||
void update_used_tables() {}
|
||||
table_map not_null_tables() const { return 0; }
|
||||
bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
|
||||
|
@ -1008,28 +1007,6 @@ 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; }
|
||||
const char *func_name() const { return "match_nl"; }
|
||||
};
|
||||
|
||||
|
||||
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; }
|
||||
const char *func_name() const { return "match_bool"; }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -153,6 +153,7 @@ static SYMBOL symbols[] = {
|
|||
{ "EXECUTE", SYM(EXECUTE_SYM),0,0},
|
||||
{ "EXPLAIN", SYM(DESCRIBE),0,0},
|
||||
{ "EXISTS", SYM(EXISTS),0,0},
|
||||
{ "EXPANSION", SYM(EXPANSION_SYM),0,0},
|
||||
{ "EXTENDED", SYM(EXTENDED_SYM),0,0},
|
||||
{ "FAST", SYM(FAST_SYM),0,0},
|
||||
{ "FIELDS", SYM(COLUMNS),0,0},
|
||||
|
|
|
@ -23,16 +23,21 @@
|
|||
#include <signal.h>
|
||||
#include <thr_lock.h>
|
||||
#include <my_base.h> /* Needed by field.h */
|
||||
#include <my_bitmap.h>
|
||||
#include <sql_bitmap.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef __EMX__
|
||||
#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 */
|
||||
/* 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 +652,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 +661,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);
|
||||
|
|
|
@ -2161,7 +2161,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;
|
||||
}
|
||||
|
@ -3571,7 +3571,7 @@ enum options_mysqld
|
|||
OPT_CONNECT_TIMEOUT, OPT_DELAYED_INSERT_TIMEOUT,
|
||||
OPT_DELAYED_INSERT_LIMIT, OPT_DELAYED_QUEUE_SIZE,
|
||||
OPT_FLUSH_TIME, OPT_FT_MIN_WORD_LEN,
|
||||
OPT_FT_MAX_WORD_LEN, OPT_FT_MAX_WORD_LEN_FOR_SORT, OPT_FT_STOPWORD_FILE,
|
||||
OPT_FT_MAX_WORD_LEN, OPT_FT_QUERY_EXPANSION_LIMIT, OPT_FT_STOPWORD_FILE,
|
||||
OPT_INTERACTIVE_TIMEOUT, OPT_JOIN_BUFF_SIZE,
|
||||
OPT_KEY_BUFFER_SIZE, OPT_LONG_QUERY_TIME,
|
||||
OPT_LOWER_CASE_TABLE_NAMES, OPT_MAX_ALLOWED_PACKET,
|
||||
|
@ -4213,10 +4213,10 @@ replicating a LOAD DATA INFILE command.",
|
|||
"The maximum length of the word to be included in a FULLTEXT index. Note: FULLTEXT indexes must be rebuilt after changing this variable.",
|
||||
(gptr*) &ft_max_word_len, (gptr*) &ft_max_word_len, 0, GET_ULONG,
|
||||
REQUIRED_ARG, HA_FT_MAXLEN, 10, HA_FT_MAXLEN, 0, 1, 0},
|
||||
{ "ft_max_word_len_for_sort", OPT_FT_MAX_WORD_LEN_FOR_SORT,
|
||||
"The maximum length of the word for repair_by_sorting. Longer words are included the slow way. The lower this value, the more words will be put in one sort bucket.",
|
||||
(gptr*) &ft_max_word_len_for_sort, (gptr*) &ft_max_word_len_for_sort, 0, GET_ULONG,
|
||||
REQUIRED_ARG, 20, 4, HA_FT_MAXLEN, 0, 1, 0},
|
||||
{ "ft_query_expansion_limit", OPT_FT_QUERY_EXPANSION_LIMIT,
|
||||
"Number of best matches to use for query expansion",
|
||||
(gptr*) &ft_query_expansion_limit, (gptr*) &ft_query_expansion_limit, 0, GET_ULONG,
|
||||
REQUIRED_ARG, 20, 0, 1000, 0, 1, 0},
|
||||
{ "ft_stopword_file", OPT_FT_STOPWORD_FILE,
|
||||
"Use stopwords from this file instead of built-in list.",
|
||||
(gptr*) &ft_stopword_file, (gptr*) &ft_stopword_file, 0, GET_STR,
|
||||
|
|
|
@ -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,7 @@ 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;
|
||||
quick_keys.clear_all(); needed_reg.clear_all();
|
||||
my_b_clear(&file);
|
||||
}
|
||||
|
||||
|
@ -590,17 +590,17 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
|||
double scan_time;
|
||||
DBUG_ENTER("test_quick_select");
|
||||
DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
|
||||
(ulong) keys_to_use, (ulong) prev_tables,
|
||||
keys_to_use.to_ulonglong(), (ulong) prev_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,14 +616,14 @@ 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;
|
||||
KEY_PART *key_parts;
|
||||
PARAM param;
|
||||
|
||||
|
||||
/* set up parameter that is passed to all functions */
|
||||
param.thd= thd;
|
||||
param.baseflag=basflag;
|
||||
|
@ -650,7 +650,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 +666,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 +697,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(¶m, 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))
|
||||
{
|
||||
/*
|
||||
|
@ -744,7 +744,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
|||
my_pthread_setspecific_ptr(THR_MALLOC,old_root);
|
||||
thd->no_errors=0;
|
||||
}
|
||||
DBUG_EXECUTE("info",print_quick(quick,needed_reg););
|
||||
DBUG_EXECUTE("info",print_quick(quick,&needed_reg););
|
||||
/*
|
||||
Assume that if the user is using 'limit' we will only need to scan
|
||||
limit rows if we are using a key
|
||||
|
@ -2128,7 +2128,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;
|
||||
}
|
||||
|
@ -2854,7 +2854,7 @@ print_key(KEY_PART *key_part,const char *key,uint used_length)
|
|||
fputc('/',DBUG_FILE);
|
||||
if (field->real_maybe_null())
|
||||
{
|
||||
length++; // null byte is not in part_length
|
||||
length++; // null byte is not in part_length
|
||||
if (*key++)
|
||||
{
|
||||
fwrite("NULL",sizeof(char),4,DBUG_FILE);
|
||||
|
@ -2870,17 +2870,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: 0x%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(~0), 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
|
||||
|
|
|
@ -556,15 +556,15 @@ struct show_var_st init_vars[]= {
|
|||
{"ft_boolean_syntax", (char*) ft_boolean_syntax, SHOW_CHAR},
|
||||
{"ft_min_word_len", (char*) &ft_min_word_len, SHOW_LONG},
|
||||
{"ft_max_word_len", (char*) &ft_max_word_len, SHOW_LONG},
|
||||
{"ft_max_word_len_for_sort",(char*) &ft_max_word_len_for_sort, SHOW_LONG},
|
||||
{"ft_query_expansion_limit",(char*) &ft_query_expansion_limit, SHOW_LONG},
|
||||
{"ft_stopword_file", (char*) &ft_stopword_file, SHOW_CHAR_PTR},
|
||||
{"have_bdb", (char*) &have_berkeley_db, SHOW_HAVE},
|
||||
{"have_crypt", (char*) &have_crypt, SHOW_HAVE},
|
||||
{"have_compress", (char*) &have_compress, SHOW_HAVE},
|
||||
{"have_innodb", (char*) &have_innodb, SHOW_HAVE},
|
||||
{"have_isam", (char*) &have_isam, SHOW_HAVE},
|
||||
{"have_isam", (char*) &have_isam, SHOW_HAVE},
|
||||
{"have_raid", (char*) &have_raid, SHOW_HAVE},
|
||||
{"have_symlink", (char*) &have_symlink, SHOW_HAVE},
|
||||
{"have_symlink", (char*) &have_symlink, SHOW_HAVE},
|
||||
{"have_openssl", (char*) &have_openssl, SHOW_HAVE},
|
||||
{"have_query_cache", (char*) &have_query_cache, SHOW_HAVE},
|
||||
{"init_file", (char*) &opt_init_file, SHOW_CHAR_PTR},
|
||||
|
|
|
@ -292,3 +292,4 @@ character-set=latin2
|
|||
"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"
|
||||
|
|
|
@ -286,3 +286,4 @@ character-set=latin1
|
|||
"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"
|
||||
|
|
|
@ -294,3 +294,4 @@ character-set=latin1
|
|||
"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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -288,3 +288,4 @@ character-set=latin7
|
|||
"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"
|
||||
|
|
|
@ -283,3 +283,4 @@ character-set=latin1
|
|||
"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"
|
||||
|
|
|
@ -295,3 +295,4 @@ character-set=latin1
|
|||
"Es wird empfohlen, mit --skip-slave-start zu starten, wenn mit START SLAVE UNTIL eine Schritt-für-Schritt-Replikation ausgeführt wird. Ansonsten gibt es Probleme, wenn der Slave-Server unerwartet neu startet",
|
||||
"SQL-Thread soll nicht gestartet werden. Daher werden UNTIL-Optionen ignoriert"
|
||||
"Incorrect index name '%-.100s'",
|
||||
"Column '%-.64s' cannot be part of FULLTEXT index"
|
||||
|
|
|
@ -283,3 +283,4 @@ character-set=greek
|
|||
"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"
|
||||
|
|
|
@ -285,3 +285,4 @@ character-set=latin2
|
|||
"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"
|
||||
|
|
|
@ -283,3 +283,4 @@ character-set=latin1
|
|||
"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"
|
||||
|
|
|
@ -285,3 +285,4 @@ character-set=ujis
|
|||
"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"
|
||||
|
|
|
@ -283,3 +283,4 @@ character-set=euckr
|
|||
"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"
|
||||
|
|
|
@ -285,3 +285,4 @@ character-set=latin1
|
|||
"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"
|
||||
|
|
|
@ -285,3 +285,4 @@ character-set=latin1
|
|||
"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"
|
||||
|
|
|
@ -287,3 +287,4 @@ character-set=latin2
|
|||
"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"
|
||||
|
|
|
@ -284,3 +284,4 @@ character-set=latin1
|
|||
"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"
|
||||
|
|
|
@ -287,3 +287,4 @@ character-set=latin2
|
|||
"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"
|
||||
|
|
|
@ -285,3 +285,4 @@ character-set=koi8r
|
|||
"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"
|
||||
|
|
|
@ -278,3 +278,4 @@ character-set=cp1250
|
|||
"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"
|
||||
|
|
|
@ -291,3 +291,4 @@ character-set=latin2
|
|||
"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"
|
||||
|
|
|
@ -285,3 +285,4 @@ character-set=latin1
|
|||
"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"
|
||||
|
|
|
@ -283,3 +283,4 @@ character-set=latin1
|
|||
"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"
|
||||
|
|
|
@ -288,3 +288,4 @@ character-set=koi8u
|
|||
"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;
|
||||
}
|
||||
}
|
||||
|
|
108
sql/sql_bitmap.h
Normal file
108
sql/sql_bitmap.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include <my_global.h>
|
||||
//#include <mysql_version.h>
|
||||
//#include <mysql_embed.h>
|
||||
//#include <my_sys.h>
|
||||
//#include <m_string.h>
|
||||
//#include <hash.h>
|
||||
//#include <signal.h>
|
||||
//#include <thr_lock.h>
|
||||
//#include <my_base.h>
|
||||
#include <my_bitmap.h>
|
||||
#include <assert.h>
|
||||
|
||||
template <uint default_width> class Bitmap
|
||||
{
|
||||
MY_BITMAP map;
|
||||
uchar buffer[(default_width+7)/8];
|
||||
public:
|
||||
Bitmap() { init(); }
|
||||
Bitmap(uint prefix_to_set) { init(prefix_to_set); }
|
||||
void init() { bitmap_init(&map, buffer, default_width, 0); }
|
||||
void init(uint prefix_to_set) { init(); set_prefix(prefix_to_set); }
|
||||
uint length() const { return default_width; }
|
||||
Bitmap& operator=(const Bitmap& map2)
|
||||
{
|
||||
init();
|
||||
memcpy(buffer, map2.buffer, sizeof(buffer));
|
||||
}
|
||||
void set_bit(uint n) { bitmap_set_bit(&map, n); }
|
||||
void clear_bit(uint n) { bitmap_clear_bit(&map, n); }
|
||||
void set_prefix(uint n) { bitmap_set_prefix(&map, n); }
|
||||
void set_all() { bitmap_set_all(&map); }
|
||||
void clear_all() { bitmap_clear_all(&map); }
|
||||
void intersect(Bitmap& map2) { bitmap_intersect(&map, &map2.map); }
|
||||
void intersect(ulonglong map2buff)
|
||||
{
|
||||
MY_BITMAP map2;
|
||||
bitmap_init(&map2, (uchar *)&map2buff, sizeof(ulonglong)*8, 0);
|
||||
bitmap_intersect(&map, &map2);
|
||||
}
|
||||
void subtract(Bitmap& map2) { bitmap_subtract(&map, &map2.map); }
|
||||
void merge(Bitmap& map2) { bitmap_union(&map, &map2.map); }
|
||||
my_bool is_set(uint n) const { return bitmap_is_set(&map, n); }
|
||||
my_bool is_prefix(uint n) const { return bitmap_is_prefix(&map, n); }
|
||||
my_bool is_clear_all() const { return bitmap_is_clear_all(&map); }
|
||||
my_bool is_set_all() const { return bitmap_is_set_all(&map); }
|
||||
my_bool is_subset(const Bitmap& map2) const { return bitmap_is_subset(&map, &map2.map); }
|
||||
my_bool operator==(const Bitmap& map2) const { return bitmap_cmp(&map, &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) >= 8)
|
||||
return uint8korr(buffer);
|
||||
DBUG_ASSERT(sizeof(buffer) >= 4);
|
||||
uint4korr(buffer);
|
||||
}
|
||||
};
|
||||
|
||||
template <> class Bitmap<64>
|
||||
{
|
||||
ulonglong map;
|
||||
public:
|
||||
Bitmap<64>() { }
|
||||
Bitmap<64>(uint prefix_to_set) { set_prefix(prefix_to_set); }
|
||||
void init() { }
|
||||
void init(uint prefix_to_set) { set_prefix(prefix_to_set); }
|
||||
uint length() const { return 64; }
|
||||
void set_bit(uint n) { map|= ((ulonglong)1) << n; }
|
||||
void clear_bit(uint n) { map&= ~(((ulonglong)1) << n); }
|
||||
void set_prefix(uint n)
|
||||
{
|
||||
if (n >= length())
|
||||
set_all();
|
||||
else
|
||||
map= (((ulonglong)1) << n)-1;
|
||||
}
|
||||
void set_all() { map=~(ulonglong)0; }
|
||||
void clear_all() { map=(ulonglong)0; }
|
||||
void intersect(Bitmap<64>& map2) { map&= map2.map; }
|
||||
void intersect(ulonglong map2) { map&= map2; }
|
||||
void subtract(Bitmap<64>& map2) { map&= ~map2.map; }
|
||||
void merge(Bitmap<64>& map2) { map|= map2.map; }
|
||||
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; }
|
||||
};
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -35,6 +35,9 @@ const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
|
|||
"ref_or_null","unique_subquery","index_subquery"
|
||||
};
|
||||
|
||||
const key_map key_map_empty(0);
|
||||
const key_map key_map_full(~0);
|
||||
|
||||
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
|
||||
static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
|
||||
DYNAMIC_ARRAY *keyuse);
|
||||
|
@ -114,7 +117,7 @@ static int join_read_next_same_or_null(READ_RECORD *info);
|
|||
static COND *make_cond_for_table(COND *cond,table_map table,
|
||||
table_map used_table);
|
||||
static Item* part_of_refkey(TABLE *form,Field *field);
|
||||
static uint find_shortest_key(TABLE *table, key_map usable_keys);
|
||||
static uint find_shortest_key(TABLE *table, const key_map *usable_keys);
|
||||
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
|
||||
ha_rows select_limit, bool no_changes);
|
||||
static int create_sort_index(THD *thd, JOIN *join, ORDER *order,
|
||||
|
@ -526,7 +529,7 @@ JOIN::optimize()
|
|||
conds= optimize_cond(conds,&cond_value);
|
||||
if (thd->net.report_error)
|
||||
{
|
||||
error= 1;
|
||||
error= 1;
|
||||
DBUG_PRINT("error",("Error from optimize_cond"));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
@ -556,7 +559,7 @@ JOIN::optimize()
|
|||
if (res < 0)
|
||||
{
|
||||
zero_result_cause= "No matching min/max row";
|
||||
error=0;
|
||||
error=0;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
zero_result_cause= "Select tables optimized away";
|
||||
|
@ -703,7 +706,7 @@ JOIN::optimize()
|
|||
/*
|
||||
Force MySQL to read the table in sorted order to get result in
|
||||
ORDER BY order.
|
||||
*/
|
||||
*/
|
||||
tmp_table_param.quick_group=0;
|
||||
}
|
||||
order=0;
|
||||
|
@ -765,7 +768,7 @@ JOIN::optimize()
|
|||
make_join_readinfo(this,
|
||||
(select_options & (SELECT_DESCRIBE |
|
||||
SELECT_NO_JOIN_CACHE)) |
|
||||
(select_lex->ftfunc_list->elements ?
|
||||
(select_lex->ftfunc_list->elements ?
|
||||
SELECT_NO_JOIN_CACHE : 0));
|
||||
|
||||
/*
|
||||
|
@ -831,7 +834,7 @@ JOIN::optimize()
|
|||
conds,
|
||||
1)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
/*
|
||||
Need to tell Innobase that to play it safe, it should fetch all
|
||||
|
@ -1494,7 +1497,7 @@ JOIN::cleanup()
|
|||
|
||||
int
|
||||
mysql_select(THD *thd, Item ***rref_pointer_array,
|
||||
TABLE_LIST *tables, uint wild_num, List<Item> &fields,
|
||||
TABLE_LIST *tables, uint wild_num, List<Item> &fields,
|
||||
COND *conds, uint og_num, ORDER *order, ORDER *group,
|
||||
Item *having, ORDER *proc_param, ulong select_options,
|
||||
select_result *result, SELECT_LEX_UNIT *unit,
|
||||
|
@ -1558,7 +1561,7 @@ err:
|
|||
JOIN *curr_join= (join->need_tmp&&join->tmp_join?
|
||||
(join->tmp_join->error=join->error,join->tmp_join):
|
||||
join);
|
||||
|
||||
|
||||
thd->proc_info="end";
|
||||
err= join->cleanup();
|
||||
if (thd->net.report_error)
|
||||
|
@ -1576,7 +1579,7 @@ err:
|
|||
|
||||
static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
|
||||
TABLE *table,
|
||||
key_map keys,ha_rows limit)
|
||||
const key_map& keys,ha_rows limit)
|
||||
{
|
||||
int error;
|
||||
DBUG_ENTER("get_quick_record_count");
|
||||
|
@ -1638,9 +1641,13 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
|
|||
{
|
||||
TABLE *table;
|
||||
stat_vector[i]=s;
|
||||
s->keys.init();
|
||||
s->const_keys.init();
|
||||
s->checked_keys.init();
|
||||
s->needed_reg.init();
|
||||
table_vector[i]=s->table=table=tables->table;
|
||||
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);// record count
|
||||
table->quick_keys=0;
|
||||
table->quick_keys.clear_all();
|
||||
table->reginfo.join_tab=s;
|
||||
table->reginfo.not_exists_optimize=0;
|
||||
bzero((char*) table->const_key_parts, sizeof(key_part_map)*table->keys);
|
||||
|
@ -1786,24 +1793,25 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
|
|||
{
|
||||
start_keyuse=keyuse;
|
||||
key=keyuse->key;
|
||||
s->keys|= (key_map) 1 << key; // QQ: remove this ?
|
||||
s->keys.set_bit(key); // QQ: remove this ?
|
||||
|
||||
refs=const_ref=0;
|
||||
eq_part=0;
|
||||
refs=0;
|
||||
const_ref.clear_all();
|
||||
eq_part.clear_all();
|
||||
do
|
||||
{
|
||||
if (keyuse->val->type() != Item::NULL_ITEM && !keyuse->optimize)
|
||||
{
|
||||
if (!((~found_const_table_map) & keyuse->used_tables))
|
||||
const_ref|= (key_map) 1 << keyuse->keypart;
|
||||
const_ref.set_bit(keyuse->keypart);
|
||||
else
|
||||
refs|=keyuse->used_tables;
|
||||
eq_part|= (key_map) 1 << keyuse->keypart;
|
||||
eq_part.set_bit(keyuse->keypart);
|
||||
}
|
||||
keyuse++;
|
||||
} while (keyuse->table == table && keyuse->key == key);
|
||||
|
||||
if (eq_part == PREV_BITS(uint,table->key_info[key].key_parts) &&
|
||||
if (eq_part.is_prefix(table->key_info[key].key_parts) &&
|
||||
(table->key_info[key].flags & HA_NOSAME) &&
|
||||
!table->fulltext_searched)
|
||||
{
|
||||
|
@ -1859,7 +1867,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
|
|||
if (s->worst_seeks < 2.0) // Fix for small tables
|
||||
s->worst_seeks=2.0;
|
||||
|
||||
if (s->const_keys)
|
||||
if (! s->const_keys.is_clear_all())
|
||||
{
|
||||
ha_rows records;
|
||||
SQL_SELECT *select;
|
||||
|
@ -2096,9 +2104,10 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
|
|||
else
|
||||
{
|
||||
JOIN_TAB *stat=field->table->reginfo.join_tab;
|
||||
key_map possible_keys= (field->key_start &
|
||||
field->table->keys_in_use_for_query);
|
||||
stat[0].keys|= possible_keys; // Add possible keys
|
||||
key_map possible_keys;
|
||||
possible_keys=field->key_start;
|
||||
possible_keys.intersect(field->table->keys_in_use_for_query);
|
||||
stat[0].keys.merge(possible_keys); // Add possible keys
|
||||
|
||||
/*
|
||||
Save the following cases:
|
||||
|
@ -2117,7 +2126,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
|
|||
for (uint i=0; i<num_values; i++)
|
||||
is_const&= (*value)->const_item();
|
||||
if (is_const)
|
||||
stat[0].const_keys |= possible_keys;
|
||||
stat[0].const_keys.merge(possible_keys);
|
||||
/*
|
||||
We can't always use indexes when comparing a string index to a
|
||||
number. cmp_type() is checked to allow compare of dates to numbers.
|
||||
|
@ -2248,14 +2257,13 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
|
|||
*/
|
||||
|
||||
static uint
|
||||
max_part_bit(key_map bits)
|
||||
max_part_bit(key_part_map bits)
|
||||
{
|
||||
uint found;
|
||||
for (found=0; bits & 1 ; found++,bits>>=1) ;
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
|
||||
{
|
||||
|
@ -2267,7 +2275,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
|
|||
{
|
||||
for (uint key=0 ; key < form->keys ; key++)
|
||||
{
|
||||
if (!(form->keys_in_use_for_query & (((key_map) 1) << key)))
|
||||
if (!(form->keys_in_use_for_query.is_set(key)))
|
||||
continue;
|
||||
if (form->key_info[key].flags & HA_FULLTEXT)
|
||||
continue; // ToDo: ft-keys in non-ft queries. SerG
|
||||
|
@ -2458,7 +2466,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
|||
/* Save ptr to first use */
|
||||
if (!use->table->reginfo.join_tab->keyuse)
|
||||
use->table->reginfo.join_tab->keyuse=save_pos;
|
||||
use->table->reginfo.join_tab->checked_keys|= (key_map) 1 << use->key;
|
||||
use->table->reginfo.join_tab->checked_keys.set_bit(use->key);
|
||||
save_pos++;
|
||||
}
|
||||
i=(uint) (save_pos-(KEYUSE*) keyuse->buffer);
|
||||
|
@ -2599,7 +2607,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
|
|||
rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; // Assumed records/key
|
||||
for (keyuse=s->keyuse ; keyuse->table == table ;)
|
||||
{
|
||||
key_map found_part=0;
|
||||
key_part_map found_part=0;
|
||||
table_map found_ref=0;
|
||||
uint key=keyuse->key;
|
||||
KEY *keyinfo=table->key_info+key;
|
||||
|
@ -2668,7 +2676,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
|
|||
{
|
||||
if (!found_ref)
|
||||
{ // We found a const key
|
||||
if (table->quick_keys & ((key_map) 1 << key))
|
||||
if (table->quick_keys.is_set(key))
|
||||
records= (double) table->quick_rows[key];
|
||||
else
|
||||
{
|
||||
|
@ -2692,7 +2700,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
|
|||
/* Limit the number of matched rows */
|
||||
tmp= records;
|
||||
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
|
||||
if (table->used_keys & ((key_map) 1 << key))
|
||||
if (table->used_keys.is_set(key))
|
||||
{
|
||||
/* we can use only index tree */
|
||||
uint keys_per_block= table->file->block_size/2/
|
||||
|
@ -2719,7 +2727,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
|
|||
Check if quick_range could determinate how many rows we
|
||||
will match
|
||||
*/
|
||||
if (table->quick_keys & ((key_map) 1 << key) &&
|
||||
if (table->quick_keys.is_set(key) &&
|
||||
table->quick_key_parts[key] <= max_key_part)
|
||||
tmp=records= (double) table->quick_rows[key];
|
||||
else
|
||||
|
@ -2771,7 +2779,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
|
|||
}
|
||||
/* Limit the number of matched rows */
|
||||
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
|
||||
if (table->used_keys & ((key_map) 1 << key))
|
||||
if (table->used_keys.is_set(key))
|
||||
{
|
||||
/* we can use only index tree */
|
||||
uint keys_per_block= table->file->block_size/2/
|
||||
|
@ -2810,7 +2818,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
|
|||
!(s->quick && best_key && s->quick->index == best_key->key &&
|
||||
best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&
|
||||
!((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) &&
|
||||
s->table->used_keys && best_key) &&
|
||||
! s->table->used_keys.is_clear_all() && best_key) &&
|
||||
!(s->table->force_index && best_key))
|
||||
{ // Check full join
|
||||
ha_rows rnd_records= s->found_records;
|
||||
|
@ -3024,7 +3032,7 @@ get_best_combination(JOIN *join)
|
|||
|
||||
if (j->type == JT_SYSTEM)
|
||||
continue;
|
||||
if (!j->keys || !(keyuse= join->best_positions[tablenr].key))
|
||||
if (j->keys.is_clear_all() || !(keyuse= join->best_positions[tablenr].key))
|
||||
{
|
||||
j->type=JT_ALL;
|
||||
if (tablenr != join->const_tables)
|
||||
|
@ -3249,13 +3257,13 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
|
|||
join->row_limit=join->unit->select_limit_cnt;
|
||||
join->do_send_rows = (join->row_limit) ? 1 : 0;
|
||||
|
||||
join_tab->cache.buff=0; /* No cacheing */
|
||||
join_tab->cache.buff=0; /* No caching */
|
||||
join_tab->table=tmp_table;
|
||||
join_tab->select=0;
|
||||
join_tab->select_cond=0;
|
||||
join_tab->quick=0;
|
||||
join_tab->type= JT_ALL; /* Map through all records */
|
||||
join_tab->keys= (uint) ~0; /* test everything in quick */
|
||||
join_tab->keys.init(~0); /* test everything in quick */
|
||||
join_tab->info=0;
|
||||
join_tab->on_expr=0;
|
||||
join_tab->ref.key = -1;
|
||||
|
@ -3337,13 +3345,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||
{
|
||||
/* Use quick key read if it's a constant and it's not used
|
||||
with key reading */
|
||||
if (tab->needed_reg == 0 && tab->type != JT_EQ_REF
|
||||
if (tab->needed_reg.is_clear_all() && tab->type != JT_EQ_REF
|
||||
&& tab->type != JT_FT && (tab->type != JT_REF ||
|
||||
(uint) tab->ref.key == tab->quick->index))
|
||||
{
|
||||
sel->quick=tab->quick; // Use value from get_quick_...
|
||||
sel->quick_keys=0;
|
||||
sel->needed_reg=0;
|
||||
sel->quick_keys.clear_all();
|
||||
sel->needed_reg.clear_all();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3354,12 +3362,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||
uint ref_key=(uint) sel->head->reginfo.join_tab->ref.key+1;
|
||||
if (i == join->const_tables && ref_key)
|
||||
{
|
||||
if (tab->const_keys && tab->table->reginfo.impossible_range)
|
||||
if (!tab->const_keys.is_clear_all() &&
|
||||
tab->table->reginfo.impossible_range)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
else if (tab->type == JT_ALL && ! use_quick_range)
|
||||
{
|
||||
if (tab->const_keys &&
|
||||
if (!tab->const_keys.is_clear_all() &&
|
||||
tab->table->reginfo.impossible_range)
|
||||
DBUG_RETURN(1); // Impossible range
|
||||
/*
|
||||
|
@ -3369,9 +3378,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||
the index if we are using limit and this is the first table
|
||||
*/
|
||||
|
||||
if ((tab->keys & ~ tab->const_keys && i > 0) ||
|
||||
(tab->const_keys && i == join->const_tables &&
|
||||
join->unit->select_limit_cnt <
|
||||
if ((!tab->keys.is_subset(tab->const_keys) && i > 0) ||
|
||||
(!tab->const_keys.is_clear_all() && i == join->const_tables &&
|
||||
join->unit->select_limit_cnt <
|
||||
join->best_positions[i].records_read &&
|
||||
!(join->select_options & OPTION_FOUND_ROWS)))
|
||||
{
|
||||
|
@ -3409,13 +3418,15 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||
else
|
||||
{
|
||||
sel->needed_reg=tab->needed_reg;
|
||||
sel->quick_keys=0;
|
||||
sel->quick_keys.clear_all();
|
||||
}
|
||||
if ((sel->quick_keys | sel->needed_reg) & ~tab->checked_keys)
|
||||
if (!sel->quick_keys.is_subset(tab->checked_keys) ||
|
||||
!sel->needed_reg.is_subset(tab->checked_keys))
|
||||
{
|
||||
tab->keys=sel->quick_keys | sel->needed_reg;
|
||||
tab->use_quick= (sel->needed_reg &&
|
||||
(!select->quick_keys ||
|
||||
tab->keys=sel->quick_keys;
|
||||
tab->keys.merge(sel->needed_reg);
|
||||
tab->use_quick= (!sel->needed_reg.is_clear_all() &&
|
||||
(select->quick_keys.is_clear_all() ||
|
||||
(select->quick &&
|
||||
(select->quick->records >= 100L)))) ?
|
||||
2 : 1;
|
||||
|
@ -3480,7 +3491,7 @@ make_join_readinfo(JOIN *join, uint options)
|
|||
table->file->index_init(tab->ref.key);
|
||||
tab->read_first_record= join_read_key;
|
||||
tab->read_record.read_record= join_no_more_records;
|
||||
if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
|
||||
if (table->used_keys.is_set(tab->ref.key) &&
|
||||
!table->no_keyread)
|
||||
{
|
||||
table->key_read=1;
|
||||
|
@ -3498,7 +3509,7 @@ make_join_readinfo(JOIN *join, uint options)
|
|||
delete tab->quick;
|
||||
tab->quick=0;
|
||||
table->file->index_init(tab->ref.key);
|
||||
if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
|
||||
if (table->used_keys.is_set(tab->ref.key) &&
|
||||
!table->no_keyread)
|
||||
{
|
||||
table->key_read=1;
|
||||
|
@ -3573,14 +3584,14 @@ make_join_readinfo(JOIN *join, uint options)
|
|||
if (!table->no_keyread)
|
||||
{
|
||||
if (tab->select && tab->select->quick &&
|
||||
table->used_keys & ((key_map) 1 << tab->select->quick->index))
|
||||
table->used_keys.is_set(tab->select->quick->index))
|
||||
{
|
||||
table->key_read=1;
|
||||
table->file->extra(HA_EXTRA_KEYREAD);
|
||||
}
|
||||
else if (table->used_keys && ! (tab->select && tab->select->quick))
|
||||
else if (!table->used_keys.is_clear_all() && ! (tab->select && tab->select->quick))
|
||||
{ // Only read index tree
|
||||
tab->index=find_shortest_key(table, table->used_keys);
|
||||
tab->index=find_shortest_key(table, & table->used_keys);
|
||||
tab->table->file->index_init(tab->index);
|
||||
tab->read_first_record= join_read_first;
|
||||
tab->type=JT_NEXT; // Read with index_first / index_next
|
||||
|
@ -3924,7 +3935,7 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
|
|||
DBUG_ENTER("return_zero_rows");
|
||||
|
||||
if (select_options & SELECT_DESCRIBE)
|
||||
{
|
||||
{
|
||||
select_describe(join, false, false, false, info);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
@ -4654,6 +4665,12 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
table->db_low_byte_first=1; // True for HEAP and MyISAM
|
||||
table->temp_pool_slot = temp_pool_slot;
|
||||
table->copy_blobs= 1;
|
||||
table->keys_for_keyread.init();
|
||||
table->keys_in_use.init();
|
||||
table->read_only_keys.init();
|
||||
table->quick_keys.init();
|
||||
table->used_keys.init();
|
||||
table->keys_in_use_for_query.init();
|
||||
|
||||
/* Calculate which type of fields we will store in the temporary table */
|
||||
|
||||
|
@ -5853,7 +5870,7 @@ join_read_first(JOIN_TAB *tab)
|
|||
{
|
||||
int error;
|
||||
TABLE *table=tab->table;
|
||||
if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)) &&
|
||||
if (!table->key_read && table->used_keys.is_set(tab->index) &&
|
||||
!table->no_keyread)
|
||||
{
|
||||
table->key_read=1;
|
||||
|
@ -5890,7 +5907,7 @@ join_read_last(JOIN_TAB *tab)
|
|||
{
|
||||
TABLE *table=tab->table;
|
||||
int error;
|
||||
if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)) &&
|
||||
if (!table->key_read && table->used_keys.is_set(tab->index) &&
|
||||
!table->no_keyread)
|
||||
{
|
||||
table->key_read=1;
|
||||
|
@ -6588,18 +6605,21 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
|
|||
return reverse;
|
||||
}
|
||||
|
||||
static uint find_shortest_key(TABLE *table, key_map usable_keys)
|
||||
static uint find_shortest_key(TABLE *table, const key_map *usable_keys)
|
||||
{
|
||||
uint min_length= (uint) ~0;
|
||||
uint best= MAX_KEY;
|
||||
for (uint nr=0; usable_keys ; usable_keys>>=1, nr++)
|
||||
if (!usable_keys->is_clear_all())
|
||||
{
|
||||
if (usable_keys & 1)
|
||||
for (uint nr=0; nr < table->keys ; nr++)
|
||||
{
|
||||
if (table->key_info[nr].key_length < min_length)
|
||||
if (usable_keys->is_set(nr))
|
||||
{
|
||||
min_length=table->key_info[nr].key_length;
|
||||
best=nr;
|
||||
if (table->key_info[nr].key_length < min_length)
|
||||
{
|
||||
min_length=table->key_info[nr].key_length;
|
||||
best=nr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6645,7 +6665,7 @@ is_subkey(KEY_PART_INFO *key_part, KEY_PART_INFO *ref_key_part,
|
|||
|
||||
static uint
|
||||
test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
|
||||
key_map usable_keys)
|
||||
const key_map& usable_keys)
|
||||
{
|
||||
uint nr;
|
||||
uint min_length= (uint) ~0;
|
||||
|
@ -6653,10 +6673,10 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
|
|||
uint not_used;
|
||||
KEY_PART_INFO *ref_key_part= table->key_info[ref].key_part;
|
||||
KEY_PART_INFO *ref_key_part_end= ref_key_part + ref_key_parts;
|
||||
|
||||
for (nr= 0; usable_keys; usable_keys>>= 1, nr++)
|
||||
|
||||
for (nr= 0 ; nr < table->keys ; nr++)
|
||||
{
|
||||
if ((usable_keys & 1) &&
|
||||
if (usable_keys.is_set(nr) &&
|
||||
table->key_info[nr].key_length < min_length &&
|
||||
table->key_info[nr].key_parts >= ref_key_parts &&
|
||||
is_subkey(table->key_info[nr].key_part, ref_key_part,
|
||||
|
@ -6694,16 +6714,17 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||
LINT_INIT(ref_key_parts);
|
||||
|
||||
/* Check which keys can be used to resolve ORDER BY */
|
||||
usable_keys= ~(key_map) 0;
|
||||
usable_keys.set_all();
|
||||
for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next)
|
||||
{
|
||||
if ((*tmp_order->item)->type() != Item::FIELD_ITEM)
|
||||
{
|
||||
usable_keys=0;
|
||||
usable_keys.clear_all();
|
||||
break;
|
||||
}
|
||||
if (!(usable_keys&= (((Item_field*) (*tmp_order->item))->field->
|
||||
part_of_sortkey)))
|
||||
usable_keys.intersect(
|
||||
((Item_field*) (*tmp_order->item))->field->part_of_sortkey);
|
||||
if (usable_keys.is_clear_all())
|
||||
break; // No usable keys
|
||||
}
|
||||
|
||||
|
@ -6729,7 +6750,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||
*/
|
||||
int order_direction;
|
||||
uint used_key_parts;
|
||||
if (!(usable_keys & ((key_map) 1 << ref_key)))
|
||||
if (!usable_keys.is_set(ref_key))
|
||||
{
|
||||
/*
|
||||
We come here when ref_key is not among usable_keys
|
||||
|
@ -6739,8 +6760,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||
If using index only read, only consider other possible index only
|
||||
keys
|
||||
*/
|
||||
if (table->used_keys & (((key_map) 1 << ref_key)))
|
||||
usable_keys|= table->used_keys;
|
||||
if (table->used_keys.is_set(ref_key))
|
||||
usable_keys.merge(table->used_keys);
|
||||
if ((new_ref_key= test_if_subkey(order, table, ref_key, ref_key_parts,
|
||||
usable_keys)) < MAX_KEY)
|
||||
{
|
||||
|
@ -6756,10 +6777,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||
select->quick->init();
|
||||
}
|
||||
ref_key= new_ref_key;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Check if we get the rows in requested sorted order by using the key */
|
||||
if ((usable_keys & ((key_map) 1 << ref_key)) &&
|
||||
if (usable_keys.is_set(ref_key) &&
|
||||
(order_direction = test_if_order_by_key(order,table,ref_key,
|
||||
&used_key_parts)))
|
||||
{
|
||||
|
@ -6810,7 +6831,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||
/* check if we can use a key to resolve the group */
|
||||
/* Tables using JT_NEXT are handled here */
|
||||
uint nr;
|
||||
key_map keys=usable_keys;
|
||||
key_map keys;
|
||||
|
||||
/*
|
||||
If not used with LIMIT, only use keys if the whole query can be
|
||||
|
@ -6818,12 +6839,19 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||
retrieving all rows through an index.
|
||||
*/
|
||||
if (select_limit >= table->file->records)
|
||||
keys&= (table->used_keys | table->file->keys_to_use_for_scanning());
|
||||
{
|
||||
keys=*table->file->keys_to_use_for_scanning();
|
||||
keys.merge(table->used_keys);
|
||||
}
|
||||
else
|
||||
keys.set_all();
|
||||
|
||||
for (nr=0; keys ; keys>>=1, nr++)
|
||||
keys.intersect(usable_keys);
|
||||
|
||||
for (nr=0; nr < table->keys ; nr++)
|
||||
{
|
||||
uint not_used;
|
||||
if (keys & 1)
|
||||
if (keys.is_set(nr))
|
||||
{
|
||||
int flag;
|
||||
if ((flag=test_if_order_by_key(order, table, nr, ¬_used)))
|
||||
|
@ -6835,7 +6863,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||
join_read_last);
|
||||
table->file->index_init(nr);
|
||||
tab->type=JT_NEXT; // Read with index_first(), index_next()
|
||||
if (table->used_keys & ((key_map) 1 << nr))
|
||||
if (table->used_keys.is_set(nr))
|
||||
{
|
||||
table->key_read=1;
|
||||
table->file->extra(HA_EXTRA_KEYREAD);
|
||||
|
@ -6860,7 +6888,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||
order How table should be sorted
|
||||
filesort_limit Max number of rows that needs to be sorted
|
||||
select_limit Max number of rows in final output
|
||||
Used to decide if we should use index or not
|
||||
Used to decide if we should use index or not
|
||||
|
||||
|
||||
IMPLEMENTATION
|
||||
|
@ -8690,7 +8718,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||
Item *item_null= new Item_null();
|
||||
CHARSET_INFO *cs= &my_charset_latin1;
|
||||
DBUG_ENTER("select_describe");
|
||||
DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
|
||||
DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
|
||||
(ulong)join->select_lex, join->select_lex->type,
|
||||
message));
|
||||
/* Don't log this into the slow query log */
|
||||
|
@ -8724,7 +8752,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||
tmp2.length(0);
|
||||
|
||||
item_list.empty();
|
||||
item_list.push_back(new Item_int((int32)
|
||||
item_list.push_back(new Item_int((int32)
|
||||
join->select_lex->select_number));
|
||||
item_list.push_back(new Item_string(join->select_lex->type,
|
||||
strlen(join->select_lex->type),
|
||||
|
@ -8746,21 +8774,23 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||
item_list.push_back(new Item_string(join_type_str[tab->type],
|
||||
strlen(join_type_str[tab->type]),
|
||||
cs));
|
||||
key_map bits;
|
||||
uint j;
|
||||
for (j=0,bits=tab->keys ; bits ; j++,bits>>=1)
|
||||
if (!tab->keys.is_clear_all())
|
||||
{
|
||||
if (bits & 1)
|
||||
{
|
||||
if (tmp1.length())
|
||||
tmp1.append(',');
|
||||
tmp1.append(table->key_info[j].name);
|
||||
}
|
||||
for (j=0 ; j < tab->keys.length() ; j++)
|
||||
{
|
||||
if (tab->keys.is_set(j))
|
||||
{
|
||||
if (tmp1.length())
|
||||
tmp1.append(',');
|
||||
tmp1.append(table->key_info[j].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tmp1.length())
|
||||
item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs));
|
||||
else
|
||||
item_list.push_back(item_null);
|
||||
item_list.push_back(item_null);
|
||||
if (tab->ref.key_parts)
|
||||
{
|
||||
KEY *key_info=table->key_info+ tab->ref.key;
|
||||
|
@ -8803,10 +8833,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||
join->best_positions[i]. records_read,
|
||||
21));
|
||||
my_bool key_read=table->key_read;
|
||||
if (tab->type == JT_NEXT &&
|
||||
((table->used_keys & ((key_map) 1 << tab->index))))
|
||||
if (tab->type == JT_NEXT && table->used_keys.is_set(tab->index))
|
||||
key_read=1;
|
||||
|
||||
|
||||
if (tab->info)
|
||||
item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
|
||||
else
|
||||
|
@ -8815,8 +8844,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||
{
|
||||
if (tab->use_quick == 2)
|
||||
{
|
||||
sprintf(buff_ptr,"; Range checked for each record (index map: %u)",
|
||||
tab->keys);
|
||||
char buf[MAX_KEY/8+1];
|
||||
sprintf(buff_ptr,"; Range checked for each record (index map: 0x%s)",
|
||||
tab->keys.print(buf));
|
||||
buff_ptr=strend(buff_ptr);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -938,7 +938,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);
|
||||
|
|
137
sql/sql_table.cc
137
sql/sql_table.cc
|
@ -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> ¬_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> ¬_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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,6 +135,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||
%token DROP
|
||||
%token EVENTS_SYM
|
||||
%token EXECUTE_SYM
|
||||
%token EXPANSION_SYM
|
||||
%token FLUSH_SYM
|
||||
%token HELP_SYM
|
||||
%token INSERT
|
||||
|
@ -168,7 +169,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||
%token SUPER_SYM
|
||||
%token TRUNCATE_SYM
|
||||
%token UNLOCK_SYM
|
||||
%token UNTIL_SYM
|
||||
%token UNTIL_SYM
|
||||
%token UPDATE_SYM
|
||||
|
||||
%token ACTION
|
||||
|
@ -604,8 +605,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||
%type <num>
|
||||
type int_type real_type order_dir opt_field_spec lock_option
|
||||
udf_type if_exists opt_local opt_table_options table_options
|
||||
table_option opt_if_not_exists opt_no_write_to_binlog opt_var_type opt_var_ident_type
|
||||
delete_option opt_temporary all_or_any opt_distinct opt_ignore_leaves
|
||||
table_option opt_if_not_exists opt_no_write_to_binlog opt_var_type
|
||||
opt_var_ident_type delete_option opt_temporary all_or_any opt_distinct
|
||||
opt_ignore_leaves fulltext_options
|
||||
|
||||
%type <ulong_num>
|
||||
ULONG_NUM raid_types merge_insert_types
|
||||
|
@ -2433,12 +2435,10 @@ simple_expr:
|
|||
| EXISTS exists_subselect { $$= $2; }
|
||||
| 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))); }
|
||||
| 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))); }
|
||||
| MATCH ident_list_arg AGAINST '(' expr fulltext_options ')'
|
||||
{ $2->push_front($5);
|
||||
Select->add_ftfunc_to_list((Item_func_match*)
|
||||
($$=new Item_func_match(*$2,$6))); }
|
||||
| ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); }
|
||||
| BINARY expr %prec NEG
|
||||
{
|
||||
|
@ -2446,10 +2446,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 ); }
|
||||
|
@ -2826,6 +2826,12 @@ simple_expr:
|
|||
| EXTRACT_SYM '(' interval FROM expr ')'
|
||||
{ $$=new Item_extract( $3, $5); };
|
||||
|
||||
fulltext_options:
|
||||
/* nothing */ { $$= FT_NL; }
|
||||
| WITH QUERY_SYM EXPANSION_SYM { $$= FT_NL | FT_EXPAND; }
|
||||
| IN_SYM BOOLEAN_SYM MODE_SYM { $$= FT_BOOL; }
|
||||
;
|
||||
|
||||
udf_expr_list:
|
||||
/* empty */ { $$= NULL; }
|
||||
| expr_list { $$= $1;};
|
||||
|
@ -2952,7 +2958,7 @@ ident_list2:
|
|||
|
||||
opt_expr:
|
||||
/* empty */ { $$= NULL; }
|
||||
| expr { $$= $1; };
|
||||
| expr { $$= $1; };
|
||||
|
||||
opt_else:
|
||||
/* empty */ { $$= NULL; }
|
||||
|
@ -4525,6 +4531,7 @@ keyword:
|
|||
| ESCAPE_SYM {}
|
||||
| EVENTS_SYM {}
|
||||
| EXECUTE_SYM {}
|
||||
| EXPANSION_SYM {}
|
||||
| EXTENDED_SYM {}
|
||||
| FAST_SYM {}
|
||||
| DISABLE_SYM {}
|
||||
|
|
41
sql/table.cc
41
sql/table.cc
|
@ -137,10 +137,11 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
|
|||
outparam->raid_type= head[41];
|
||||
outparam->raid_chunks= head[42];
|
||||
outparam->raid_chunksize= uint4korr(head+43);
|
||||
if (!(outparam->table_charset=get_charset((uint) head[38],MYF(0))))
|
||||
outparam->table_charset=default_charset_info; // QQ display error message?
|
||||
outparam->table_charset=get_charset((uint) head[38],MYF(0));
|
||||
null_field_first=1;
|
||||
}
|
||||
if (!outparam->table_charset) /* unknown charset in head[38] or pre-3.23 frm */
|
||||
outparam->table_charset=default_charset_info;
|
||||
outparam->db_record_offset=1;
|
||||
if (db_create_options & HA_OPTION_LONG_BLOB_PTR)
|
||||
outparam->blob_ptr_size=portable_sizeof_char_ptr;
|
||||
|
@ -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(keys);
|
||||
outparam->keys_in_use.init(keys);
|
||||
outparam->read_only_keys.init(0);
|
||||
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;
|
||||
|
|
Loading…
Add table
Reference in a new issue