Commit abc24043 authored by unknown's avatar unknown
Browse files

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
Loading
Loading
Loading
Loading
+23 −16
Original line number Diff line number Diff line
@@ -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
{
  MYSQL_FTPARSER_PARAM *up;
  FTB *ftb;
  FTB_EXPR *ftbe;
  byte *up_quot;
@@ -280,7 +281,7 @@ static int ftb_parse_query_internal(void *param, char *query, int len)
  info.prev= ' ';
  info.quot= 0;
  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);
}

@@ -295,14 +296,15 @@ static void _ftb_parse_query(FTB *ftb, byte *query, uint len,

  if (ftb->state != UNINITIALIZED)
    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.depth= 0;
  ftb_param.ftbe= ftb->root;
  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_add_word= ftb_query_add_word;
  param->mysql_ftparam= (void *)&ftb_param;
@@ -569,6 +571,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query,

typedef struct st_my_ftb_phrase_param
{
  MYSQL_FTPARSER_PARAM *up;
  LIST *phrase;
  LIST *document;
  CHARSET_INFO *cs;
@@ -615,7 +618,7 @@ static int ftb_check_phrase_internal(void *param, char *document, int len)
  const char *docend= document + len;
  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)
      return 1;
  }
@@ -644,8 +647,11 @@ static int _ftb_check_phrase(FTB *ftb, const byte *document, uint len,
  MYSQL_FTPARSER_PARAM *param;
  DBUG_ENTER("_ftb_check_phrase");
  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);

  ftb_param.up= param;
  ftb_param.phrase= ftbe->phrase;
  ftb_param.document= ftbe->document;
  ftb_param.cs= ftb->charset;
@@ -814,6 +820,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record)

typedef struct st_my_ftb_find_param
{
  MYSQL_FTPARSER_PARAM *up;
  FT_INFO *ftb;
  FT_SEG_ITERATOR *ftsi;
} 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)
{
  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;
  FT_WORD w;
  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);
}

@@ -878,7 +886,7 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length)
    return -2.0;
  if (!ftb->queue.elements)
    return 0;
  if (! (param= ftparser_call_initializer(ftb->info, ftb->keynr)))
  if (! (param= ftparser_call_initializer(ftb->info, ftb->keynr, 0)))
    return 0;

  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);
  memcpy(&ftsi2, &ftsi, sizeof(ftsi));

  ftb_param.up= param;
  ftb_param.ftb= ftb;
  ftb_param.ftsi= &ftsi2;
  while (_mi_ft_segiterator(&ftsi))
  {
    if (!ftsi.pos)
      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;
  while (_mi_ft_segiterator(&ftsi))
  {
    if (!ftsi.pos)
      continue;
    param->doc= (byte *)ftsi.pos;
    param->length= ftsi.len;
    parser->parse(param);
+1 −1
Original line number Diff line number Diff line
@@ -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.keybuff=info->lastkey+info->s->base.max_key_length;
  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;

  bzero(&wtree,sizeof(wtree));
+33 −16
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ typedef struct st_ft_docstat {

typedef struct st_my_ft_parser_param
{
  MYSQL_FTPARSER_PARAM *up;
  TREE *wtree;
  my_bool with_alloc;
} 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;
  MY_FT_PARSER_PARAM *ft_param=(MY_FT_PARSER_PARAM *)param;
  TREE *wtree= ft_param->wtree;
  FT_WORD w;
  TREE *wtree;
  DBUG_ENTER("ft_parse_internal");

  wtree= ((MY_FT_PARSER_PARAM *)param)->wtree;
  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(0);
}
@@ -290,6 +291,8 @@ int ft_parse(TREE *wtree, byte *doc, int doclen, my_bool with_alloc,
  MY_FT_PARSER_PARAM my_param;
  DBUG_ENTER("ft_parse");
  DBUG_ASSERT(parser);

  my_param.up= param;
  my_param.wtree= wtree;
  my_param.with_alloc= with_alloc;

@@ -303,8 +306,9 @@ int ft_parse(TREE *wtree, byte *doc, int doclen, my_bool with_alloc,
  DBUG_RETURN(parser->parse(param));
}


MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info, uint keynr)
#define MAX_PARAM_NR 2
MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info,
                                                uint keynr, uint paramnr)
{
  uint32 ftparser_nr;
  struct st_mysql_ftparser *parser;
@@ -343,8 +347,14 @@ MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info, uint keynr)
      }
      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 *)
      my_malloc(sizeof(MYSQL_FTPARSER_PARAM) *
      my_malloc(MAX_PARAM_NR * sizeof(MYSQL_FTPARSER_PARAM) *
                info->s->ftparsers, MYF(MY_WME|MY_ZEROFILL));
    if (! info->ftparser_param)
      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;
    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)
  {
    /* 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];
}


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)
    return;
  for (i= 0; i < keys; i++)
  {
    MI_KEYDEF *keyinfo= &info->s->keyinfo[i];
    for (j=0; j < MAX_PARAM_NR; j++)
    {
      MYSQL_FTPARSER_PARAM *ftparser_param=
      &info->ftparser_param[keyinfo->ftparser_nr];
        &info->ftparser_param[keyinfo->ftparser_nr*MAX_PARAM_NR + j];
      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;
    }
  }
}
+1 −1
Original line number Diff line number Diff line
@@ -122,7 +122,7 @@ FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, const byte *record)
  TREE ptree;
  MYSQL_FTPARSER_PARAM *param;
  DBUG_ENTER("_mi_ft_parserecord");
  if (! (param= ftparser_call_initializer(info, keynr)))
  if (! (param= ftparser_call_initializer(info, keynr, 0)))
    DBUG_RETURN(NULL);
  bzero((char*) &ptree, sizeof(ptree));
  if (_mi_ft_parse(&ptree, info, keynr, record, 0, param))
+2 −1
Original line number Diff line number Diff line
@@ -145,5 +145,6 @@ float ft_boolean_get_relevance(FT_INFO *);
my_off_t ft_boolean_get_docid(FT_INFO *);
void ft_boolean_reinit_search(FT_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);