mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
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.
This commit is contained in:
@@ -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)
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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 @@ err:
|
|||||||
|
|
||||||
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)
|
|||||||
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,
|
|||||||
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 @@ err:
|
|||||||
|
|
||||||
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,
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
_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,
|
|||||||
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 {
|
|||||||
|
|
||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 *);
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user