Commit abc24043 authored by unknown's avatar unknown

Bug#18836 - fulltext parser plugin is called recursively.

Don't use the same param in recursive call.
Also, the fix makes it safe for a plugin to replace param->mysql_add_word


storage/myisam/ft_nlq_search.c:
  Bug#18836 - fulltext parser plugin is called recursively.
  Don't use the same param in recursive call.
storage/myisam/ft_update.c:
  Bug#18836 - fulltext parser plugin is called recursively.
  Don't use the same param in recursive call.
storage/myisam/ftdefs.h:
  Bug#18836 - fulltext parser plugin is called recursively.
  Don't use the same param in recursive call.
parent 89ce78f2
...@@ -160,6 +160,7 @@ static int FTB_WORD_cmp_list(CHARSET_INFO *cs, FTB_WORD **a, FTB_WORD **b) ...@@ -160,6 +160,7 @@ static int FTB_WORD_cmp_list(CHARSET_INFO *cs, FTB_WORD **a, FTB_WORD **b)
typedef struct st_my_ftb_param typedef struct st_my_ftb_param
{ {
MYSQL_FTPARSER_PARAM *up;
FTB *ftb; FTB *ftb;
FTB_EXPR *ftbe; FTB_EXPR *ftbe;
byte *up_quot; byte *up_quot;
...@@ -280,7 +281,7 @@ static int ftb_parse_query_internal(void *param, char *query, int len) ...@@ -280,7 +281,7 @@ static int ftb_parse_query_internal(void *param, char *query, int len)
info.prev= ' '; info.prev= ' ';
info.quot= 0; info.quot= 0;
while (ft_get_word(cs, start, end, &w, &info)) while (ft_get_word(cs, start, end, &w, &info))
ftb_query_add_word(param, w.pos, w.len, &info); ftb_param->up->mysql_add_word(param, w.pos, w.len, &info);
return(0); return(0);
} }
...@@ -295,14 +296,15 @@ static void _ftb_parse_query(FTB *ftb, byte *query, uint len, ...@@ -295,14 +296,15 @@ static void _ftb_parse_query(FTB *ftb, byte *query, uint len,
if (ftb->state != UNINITIALIZED) if (ftb->state != UNINITIALIZED)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
if (! (param= ftparser_call_initializer(ftb->info, ftb->keynr, 0)))
DBUG_VOID_RETURN;
ftb_param.up= param;
ftb_param.ftb= ftb; ftb_param.ftb= ftb;
ftb_param.depth= 0; ftb_param.depth= 0;
ftb_param.ftbe= ftb->root; ftb_param.ftbe= ftb->root;
ftb_param.up_quot= 0; ftb_param.up_quot= 0;
if (! (param= ftparser_call_initializer(ftb->info, ftb->keynr)))
DBUG_VOID_RETURN;
param->mysql_parse= ftb_parse_query_internal; param->mysql_parse= ftb_parse_query_internal;
param->mysql_add_word= ftb_query_add_word; param->mysql_add_word= ftb_query_add_word;
param->mysql_ftparam= (void *)&ftb_param; param->mysql_ftparam= (void *)&ftb_param;
...@@ -313,7 +315,7 @@ static void _ftb_parse_query(FTB *ftb, byte *query, uint len, ...@@ -313,7 +315,7 @@ static void _ftb_parse_query(FTB *ftb, byte *query, uint len,
parser->parse(param); parser->parse(param);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
static int _ftb_no_dupes_cmp(void* not_used __attribute__((unused)), static int _ftb_no_dupes_cmp(void* not_used __attribute__((unused)),
const void *a,const void *b) const void *a,const void *b)
...@@ -569,6 +571,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, ...@@ -569,6 +571,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query,
typedef struct st_my_ftb_phrase_param typedef struct st_my_ftb_phrase_param
{ {
MYSQL_FTPARSER_PARAM *up;
LIST *phrase; LIST *phrase;
LIST *document; LIST *document;
CHARSET_INFO *cs; CHARSET_INFO *cs;
...@@ -615,7 +618,7 @@ static int ftb_check_phrase_internal(void *param, char *document, int len) ...@@ -615,7 +618,7 @@ static int ftb_check_phrase_internal(void *param, char *document, int len)
const char *docend= document + len; const char *docend= document + len;
while (ft_simple_get_word(phrase_param->cs, &document, docend, &word, FALSE)) while (ft_simple_get_word(phrase_param->cs, &document, docend, &word, FALSE))
{ {
ftb_phrase_add_word(param, word.pos, word.len, 0); phrase_param->up->mysql_add_word(param, word.pos, word.len, 0);
if (phrase_param->match) if (phrase_param->match)
return 1; return 1;
} }
...@@ -644,8 +647,11 @@ static int _ftb_check_phrase(FTB *ftb, const byte *document, uint len, ...@@ -644,8 +647,11 @@ static int _ftb_check_phrase(FTB *ftb, const byte *document, uint len,
MYSQL_FTPARSER_PARAM *param; MYSQL_FTPARSER_PARAM *param;
DBUG_ENTER("_ftb_check_phrase"); DBUG_ENTER("_ftb_check_phrase");
DBUG_ASSERT(parser); DBUG_ASSERT(parser);
if (! (param= ftparser_call_initializer(ftb->info, ftb->keynr)))
if (! (param= ftparser_call_initializer(ftb->info, ftb->keynr, 1)))
DBUG_RETURN(0); DBUG_RETURN(0);
ftb_param.up= param;
ftb_param.phrase= ftbe->phrase; ftb_param.phrase= ftbe->phrase;
ftb_param.document= ftbe->document; ftb_param.document= ftbe->document;
ftb_param.cs= ftb->charset; ftb_param.cs= ftb->charset;
...@@ -814,6 +820,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) ...@@ -814,6 +820,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record)
typedef struct st_my_ftb_find_param typedef struct st_my_ftb_find_param
{ {
MYSQL_FTPARSER_PARAM *up;
FT_INFO *ftb; FT_INFO *ftb;
FT_SEG_ITERATOR *ftsi; FT_SEG_ITERATOR *ftsi;
} MY_FTB_FIND_PARAM; } MY_FTB_FIND_PARAM;
...@@ -854,11 +861,12 @@ static int ftb_find_relevance_add_word(void *param, char *word, int len, ...@@ -854,11 +861,12 @@ static int ftb_find_relevance_add_word(void *param, char *word, int len,
static int ftb_find_relevance_parse(void *param, char *doc, int len) static int ftb_find_relevance_parse(void *param, char *doc, int len)
{ {
FT_INFO *ftb= ((MY_FTB_FIND_PARAM *)param)->ftb; MY_FTB_FIND_PARAM *ftb_param=(MY_FTB_FIND_PARAM *)param;
FT_INFO *ftb= ftb_param->ftb;
char *end= doc + len; char *end= doc + len;
FT_WORD w; FT_WORD w;
while (ft_simple_get_word(ftb->charset, &doc, end, &w, TRUE)) while (ft_simple_get_word(ftb->charset, &doc, end, &w, TRUE))
ftb_find_relevance_add_word(param, w.pos, w.len, 0); ftb_param->up->mysql_add_word(param, w.pos, w.len, 0);
return(0); return(0);
} }
...@@ -878,7 +886,7 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) ...@@ -878,7 +886,7 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length)
return -2.0; return -2.0;
if (!ftb->queue.elements) if (!ftb->queue.elements)
return 0; return 0;
if (! (param= ftparser_call_initializer(ftb->info, ftb->keynr))) if (! (param= ftparser_call_initializer(ftb->info, ftb->keynr, 0)))
return 0; return 0;
if (ftb->state != INDEX_SEARCH && docid <= ftb->lastpos) if (ftb->state != INDEX_SEARCH && docid <= ftb->lastpos)
...@@ -902,19 +910,18 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) ...@@ -902,19 +910,18 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length)
_mi_ft_segiterator_init(ftb->info, ftb->keynr, record, &ftsi); _mi_ft_segiterator_init(ftb->info, ftb->keynr, record, &ftsi);
memcpy(&ftsi2, &ftsi, sizeof(ftsi)); memcpy(&ftsi2, &ftsi, sizeof(ftsi));
ftb_param.up= param;
ftb_param.ftb= ftb; ftb_param.ftb= ftb;
ftb_param.ftsi= &ftsi2; ftb_param.ftsi= &ftsi2;
param->mysql_parse= ftb_find_relevance_parse;
param->mysql_add_word= ftb_find_relevance_add_word;
param->mysql_ftparam= (void *)&ftb_param;
param->cs= ftb->charset;
param->mode= MYSQL_FTPARSER_SIMPLE_MODE;
while (_mi_ft_segiterator(&ftsi)) while (_mi_ft_segiterator(&ftsi))
{ {
if (!ftsi.pos) if (!ftsi.pos)
continue; continue;
/* Since subsequent call to _ftb_check_phrase overwrites param elements,
it must be reinitialized at each iteration _inside_ the loop. */
param->mysql_parse= ftb_find_relevance_parse;
param->mysql_add_word= ftb_find_relevance_add_word;
param->mysql_ftparam= (void *)&ftb_param;
param->cs= ftb->charset;
param->mode= MYSQL_FTPARSER_SIMPLE_MODE;
param->doc= (byte *)ftsi.pos; param->doc= (byte *)ftsi.pos;
param->length= ftsi.len; param->length= ftsi.len;
parser->parse(param); parser->parse(param);
......
...@@ -226,7 +226,7 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query, ...@@ -226,7 +226,7 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query,
aio.charset=info->s->keyinfo[keynr].seg->charset; aio.charset=info->s->keyinfo[keynr].seg->charset;
aio.keybuff=info->lastkey+info->s->base.max_key_length; aio.keybuff=info->lastkey+info->s->base.max_key_length;
parser= info->s->keyinfo[keynr].parser; parser= info->s->keyinfo[keynr].parser;
if (! (ftparser_param= ftparser_call_initializer(info, keynr))) if (! (ftparser_param= ftparser_call_initializer(info, keynr, 0)))
goto err; goto err;
bzero(&wtree,sizeof(wtree)); bzero(&wtree,sizeof(wtree));
......
...@@ -27,6 +27,7 @@ typedef struct st_ft_docstat { ...@@ -27,6 +27,7 @@ typedef struct st_ft_docstat {
typedef struct st_my_ft_parser_param typedef struct st_my_ft_parser_param
{ {
MYSQL_FTPARSER_PARAM *up;
TREE *wtree; TREE *wtree;
my_bool with_alloc; my_bool with_alloc;
} MY_FT_PARSER_PARAM; } MY_FT_PARSER_PARAM;
...@@ -268,16 +269,16 @@ static int ft_add_word(void *param, byte *word, uint word_len, ...@@ -268,16 +269,16 @@ static int ft_add_word(void *param, byte *word, uint word_len,
} }
static int ft_parse_internal(void *param, byte *doc, uint doc_len) static int ft_parse_internal(void *param, byte *doc, int doc_len)
{ {
byte *end=doc+doc_len; byte *end=doc+doc_len;
MY_FT_PARSER_PARAM *ft_param=(MY_FT_PARSER_PARAM *)param;
TREE *wtree= ft_param->wtree;
FT_WORD w; FT_WORD w;
TREE *wtree;
DBUG_ENTER("ft_parse_internal"); DBUG_ENTER("ft_parse_internal");
wtree= ((MY_FT_PARSER_PARAM *)param)->wtree;
while (ft_simple_get_word(wtree->custom_arg, &doc, end, &w, TRUE)) while (ft_simple_get_word(wtree->custom_arg, &doc, end, &w, TRUE))
if (ft_add_word(param, w.pos, w.len, 0)) if (ft_param->up->mysql_add_word(param, w.pos, w.len, 0))
DBUG_RETURN(1); DBUG_RETURN(1);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -290,6 +291,8 @@ int ft_parse(TREE *wtree, byte *doc, int doclen, my_bool with_alloc, ...@@ -290,6 +291,8 @@ int ft_parse(TREE *wtree, byte *doc, int doclen, my_bool with_alloc,
MY_FT_PARSER_PARAM my_param; MY_FT_PARSER_PARAM my_param;
DBUG_ENTER("ft_parse"); DBUG_ENTER("ft_parse");
DBUG_ASSERT(parser); DBUG_ASSERT(parser);
my_param.up= param;
my_param.wtree= wtree; my_param.wtree= wtree;
my_param.with_alloc= with_alloc; my_param.with_alloc= with_alloc;
...@@ -300,11 +303,12 @@ int ft_parse(TREE *wtree, byte *doc, int doclen, my_bool with_alloc, ...@@ -300,11 +303,12 @@ int ft_parse(TREE *wtree, byte *doc, int doclen, my_bool with_alloc,
param->doc= doc; param->doc= doc;
param->length= doclen; param->length= doclen;
param->mode= MYSQL_FTPARSER_SIMPLE_MODE; param->mode= MYSQL_FTPARSER_SIMPLE_MODE;
DBUG_RETURN(parser->parse(param)); DBUG_RETURN(parser->parse(param));
} }
#define MAX_PARAM_NR 2
MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info, uint keynr) MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info,
uint keynr, uint paramnr)
{ {
uint32 ftparser_nr; uint32 ftparser_nr;
struct st_mysql_ftparser *parser; struct st_mysql_ftparser *parser;
...@@ -343,8 +347,14 @@ MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info, uint keynr) ...@@ -343,8 +347,14 @@ MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info, uint keynr)
} }
info->s->ftparsers= ftparsers; info->s->ftparsers= ftparsers;
} }
/*
We have to allocate two MYSQL_FTPARSER_PARAM structures per plugin
because in a boolean search a parser is called recursively
ftb_find_relevance* calls ftb_check_phrase*
(MAX_PARAM_NR=2)
*/
info->ftparser_param= (MYSQL_FTPARSER_PARAM *) info->ftparser_param= (MYSQL_FTPARSER_PARAM *)
my_malloc(sizeof(MYSQL_FTPARSER_PARAM) * my_malloc(MAX_PARAM_NR * sizeof(MYSQL_FTPARSER_PARAM) *
info->s->ftparsers, MYF(MY_WME|MY_ZEROFILL)); info->s->ftparsers, MYF(MY_WME|MY_ZEROFILL));
if (! info->ftparser_param) if (! info->ftparser_param)
return 0; return 0;
...@@ -359,6 +369,8 @@ MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info, uint keynr) ...@@ -359,6 +369,8 @@ MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info, uint keynr)
ftparser_nr= info->s->keyinfo[keynr].ftparser_nr; ftparser_nr= info->s->keyinfo[keynr].ftparser_nr;
parser= info->s->keyinfo[keynr].parser; parser= info->s->keyinfo[keynr].parser;
} }
DBUG_ASSERT(paramnr < MAX_PARAM_NR);
ftparser_nr= ftparser_nr*MAX_PARAM_NR + paramnr;
if (! info->ftparser_param[ftparser_nr].mysql_add_word) if (! info->ftparser_param[ftparser_nr].mysql_add_word)
{ {
/* Note, that mysql_add_word is used here as a flag: /* Note, that mysql_add_word is used here as a flag:
...@@ -372,22 +384,27 @@ MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info, uint keynr) ...@@ -372,22 +384,27 @@ MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info, uint keynr)
return &info->ftparser_param[ftparser_nr]; return &info->ftparser_param[ftparser_nr];
} }
void ftparser_call_deinitializer(MI_INFO *info) void ftparser_call_deinitializer(MI_INFO *info)
{ {
uint i, keys= info->s->state.header.keys; uint i, j, keys= info->s->state.header.keys;
if (! info->ftparser_param) if (! info->ftparser_param)
return; return;
for (i= 0; i < keys; i++) for (i= 0; i < keys; i++)
{ {
MI_KEYDEF *keyinfo= &info->s->keyinfo[i]; MI_KEYDEF *keyinfo= &info->s->keyinfo[i];
MYSQL_FTPARSER_PARAM *ftparser_param= for (j=0; j < MAX_PARAM_NR; j++)
&info->ftparser_param[keyinfo->ftparser_nr];
if (keyinfo->flag & HA_FULLTEXT && ftparser_param->mysql_add_word)
{ {
if (keyinfo->parser->deinit) MYSQL_FTPARSER_PARAM *ftparser_param=
keyinfo->parser->deinit(ftparser_param); &info->ftparser_param[keyinfo->ftparser_nr*MAX_PARAM_NR + j];
ftparser_param->mysql_add_word= 0; if (keyinfo->flag & HA_FULLTEXT && ftparser_param->mysql_add_word)
{
if (keyinfo->parser->deinit)
keyinfo->parser->deinit(ftparser_param);
ftparser_param->mysql_add_word= 0;
}
else
break;
} }
} }
} }
...@@ -122,7 +122,7 @@ FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, const byte *record) ...@@ -122,7 +122,7 @@ FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, const byte *record)
TREE ptree; TREE ptree;
MYSQL_FTPARSER_PARAM *param; MYSQL_FTPARSER_PARAM *param;
DBUG_ENTER("_mi_ft_parserecord"); DBUG_ENTER("_mi_ft_parserecord");
if (! (param= ftparser_call_initializer(info, keynr))) if (! (param= ftparser_call_initializer(info, keynr, 0)))
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
bzero((char*) &ptree, sizeof(ptree)); bzero((char*) &ptree, sizeof(ptree));
if (_mi_ft_parse(&ptree, info, keynr, record, 0, param)) if (_mi_ft_parse(&ptree, info, keynr, record, 0, param))
......
...@@ -145,5 +145,6 @@ float ft_boolean_get_relevance(FT_INFO *); ...@@ -145,5 +145,6 @@ float ft_boolean_get_relevance(FT_INFO *);
my_off_t ft_boolean_get_docid(FT_INFO *); my_off_t ft_boolean_get_docid(FT_INFO *);
void ft_boolean_reinit_search(FT_INFO *); void ft_boolean_reinit_search(FT_INFO *);
extern MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info, extern MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info,
uint keynr); uint keynr,
uint paramnr);
extern void ftparser_call_deinitializer(MI_INFO *info); extern void ftparser_call_deinitializer(MI_INFO *info);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment