~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/ft_update.c

  • Committer: Brian Aker
  • Date: 2008-07-06 08:22:57 UTC
  • mto: This revision was merged to the branch mainline in revision 78.
  • Revision ID: brian@tangent.org-20080706082257-gni9cj1cdjlqomz0
Final removal of fulltext core from myisam.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2004, 2006 MySQL AB
2
 
 
3
 
   This program is free software; you can redistribute it and/or modify
4
 
   it under the terms of the GNU General Public License as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
7
 
   This program is distributed in the hope that it will be useful,
8
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 
   GNU General Public License for more details.
11
 
 
12
 
   You should have received a copy of the GNU General Public License
13
 
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
 
 
16
 
/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
17
 
 
18
 
/* functions to work with full-text indices */
19
 
 
20
 
#include "ftdefs.h"
21
 
#include <math.h>
22
 
 
23
 
void _mi_ft_segiterator_init(MI_INFO *info, uint keynr, const uchar *record,
24
 
                             FT_SEG_ITERATOR *ftsi)
25
 
{
26
 
  DBUG_ENTER("_mi_ft_segiterator_init");
27
 
 
28
 
  ftsi->num=info->s->keyinfo[keynr].keysegs;
29
 
  ftsi->seg=info->s->keyinfo[keynr].seg;
30
 
  ftsi->rec=record;
31
 
  DBUG_VOID_RETURN;
32
 
}
33
 
 
34
 
void _mi_ft_segiterator_dummy_init(const uchar *record, uint len,
35
 
                                   FT_SEG_ITERATOR *ftsi)
36
 
{
37
 
  DBUG_ENTER("_mi_ft_segiterator_dummy_init");
38
 
 
39
 
  ftsi->num=1;
40
 
  ftsi->seg=0;
41
 
  ftsi->pos=record;
42
 
  ftsi->len=len;
43
 
  DBUG_VOID_RETURN;
44
 
}
45
 
 
46
 
/*
47
 
  This function breaks convention "return 0 in success"
48
 
  but it's easier to use like this
49
 
 
50
 
     while(_mi_ft_segiterator())
51
 
 
52
 
  so "1" means "OK", "0" means "EOF"
53
 
*/
54
 
 
55
 
uint _mi_ft_segiterator(register FT_SEG_ITERATOR *ftsi)
56
 
{
57
 
  DBUG_ENTER("_mi_ft_segiterator");
58
 
 
59
 
  if (!ftsi->num)
60
 
    DBUG_RETURN(0);
61
 
 
62
 
  ftsi->num--;
63
 
  if (!ftsi->seg)
64
 
    DBUG_RETURN(1);
65
 
 
66
 
  ftsi->seg--;
67
 
 
68
 
  if (ftsi->seg->null_bit &&
69
 
      (ftsi->rec[ftsi->seg->null_pos] & ftsi->seg->null_bit))
70
 
  {
71
 
    ftsi->pos=0;
72
 
    DBUG_RETURN(1);
73
 
  }
74
 
  ftsi->pos= ftsi->rec+ftsi->seg->start;
75
 
  if (ftsi->seg->flag & HA_VAR_LENGTH_PART)
76
 
  {
77
 
    uint pack_length= (ftsi->seg->bit_start);
78
 
    ftsi->len= (pack_length == 1 ? (uint) *(uchar*) ftsi->pos :
79
 
                uint2korr(ftsi->pos));
80
 
    ftsi->pos+= pack_length;                     /* Skip VARCHAR length */
81
 
    DBUG_RETURN(1);
82
 
  }
83
 
  if (ftsi->seg->flag & HA_BLOB_PART)
84
 
  {
85
 
    ftsi->len=_mi_calc_blob_length(ftsi->seg->bit_start,ftsi->pos);
86
 
    memcpy_fixed((char*) &ftsi->pos, ftsi->pos+ftsi->seg->bit_start,
87
 
                 sizeof(char*));
88
 
    DBUG_RETURN(1);
89
 
  }
90
 
  ftsi->len=ftsi->seg->length;
91
 
  DBUG_RETURN(1);
92
 
}
93
 
 
94
 
 
95
 
/* parses a document i.e. calls ft_parse for every keyseg */
96
 
 
97
 
uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const uchar *record,
98
 
                  MYSQL_FTPARSER_PARAM *param, MEM_ROOT *mem_root)
99
 
{
100
 
  FT_SEG_ITERATOR ftsi;
101
 
  struct st_mysql_ftparser *parser;
102
 
  DBUG_ENTER("_mi_ft_parse");
103
 
 
104
 
  _mi_ft_segiterator_init(info, keynr, record, &ftsi);
105
 
 
106
 
  ft_parse_init(parsed, info->s->keyinfo[keynr].seg->charset);
107
 
  parser= info->s->keyinfo[keynr].parser;
108
 
  while (_mi_ft_segiterator(&ftsi))
109
 
  {
110
 
    if (ftsi.pos)
111
 
      if (ft_parse(parsed, (uchar *)ftsi.pos, ftsi.len, parser, param, mem_root))
112
 
        DBUG_RETURN(1);
113
 
  }
114
 
  DBUG_RETURN(0);
115
 
}
116
 
 
117
 
FT_WORD *_mi_ft_parserecord(MI_INFO *info, uint keynr, const uchar *record,
118
 
                             MEM_ROOT *mem_root)
119
 
{
120
 
  TREE ptree;
121
 
  MYSQL_FTPARSER_PARAM *param;
122
 
  DBUG_ENTER("_mi_ft_parserecord");
123
 
  if (! (param= ftparser_call_initializer(info, keynr, 0)))
124
 
    DBUG_RETURN(NULL);
125
 
  bzero((char*) &ptree, sizeof(ptree));
126
 
  param->flags= 0;
127
 
  if (_mi_ft_parse(&ptree, info, keynr, record, param, mem_root))
128
 
    DBUG_RETURN(NULL);
129
 
 
130
 
  DBUG_RETURN(ft_linearize(&ptree, mem_root));
131
 
}
132
 
 
133
 
static int _mi_ft_store(MI_INFO *info, uint keynr, uchar *keybuf,
134
 
                        FT_WORD *wlist, my_off_t filepos)
135
 
{
136
 
  uint key_length;
137
 
  DBUG_ENTER("_mi_ft_store");
138
 
 
139
 
  for (; wlist->pos; wlist++)
140
 
  {
141
 
    key_length=_ft_make_key(info,keynr,keybuf,wlist,filepos);
142
 
    if (_mi_ck_write(info,keynr,(uchar*) keybuf,key_length))
143
 
      DBUG_RETURN(1);
144
 
   }
145
 
   DBUG_RETURN(0);
146
 
}
147
 
 
148
 
static int _mi_ft_erase(MI_INFO *info, uint keynr, uchar *keybuf,
149
 
                        FT_WORD *wlist, my_off_t filepos)
150
 
{
151
 
  uint key_length, err=0;
152
 
  DBUG_ENTER("_mi_ft_erase");
153
 
 
154
 
  for (; wlist->pos; wlist++)
155
 
  {
156
 
    key_length=_ft_make_key(info,keynr,keybuf,wlist,filepos);
157
 
    if (_mi_ck_delete(info,keynr,(uchar*) keybuf,key_length))
158
 
      err=1;
159
 
   }
160
 
   DBUG_RETURN(err);
161
 
}
162
 
 
163
 
/*
164
 
  Compares an appropriate parts of two WORD_KEY keys directly out of records
165
 
  returns 1 if they are different
166
 
*/
167
 
 
168
 
#define THOSE_TWO_DAMN_KEYS_ARE_REALLY_DIFFERENT 1
169
 
#define GEE_THEY_ARE_ABSOLUTELY_IDENTICAL        0
170
 
 
171
 
int _mi_ft_cmp(MI_INFO *info, uint keynr, const uchar *rec1, const uchar *rec2)
172
 
{
173
 
  FT_SEG_ITERATOR ftsi1, ftsi2;
174
 
  CHARSET_INFO *cs=info->s->keyinfo[keynr].seg->charset;
175
 
  DBUG_ENTER("_mi_ft_cmp");
176
 
  _mi_ft_segiterator_init(info, keynr, rec1, &ftsi1);
177
 
  _mi_ft_segiterator_init(info, keynr, rec2, &ftsi2);
178
 
 
179
 
  while (_mi_ft_segiterator(&ftsi1) && _mi_ft_segiterator(&ftsi2))
180
 
  {
181
 
    if ((ftsi1.pos != ftsi2.pos) &&
182
 
        (!ftsi1.pos || !ftsi2.pos ||
183
 
         ha_compare_text(cs, (uchar*) ftsi1.pos,ftsi1.len,
184
 
                         (uchar*) ftsi2.pos,ftsi2.len,0,0)))
185
 
      DBUG_RETURN(THOSE_TWO_DAMN_KEYS_ARE_REALLY_DIFFERENT);
186
 
  }
187
 
  DBUG_RETURN(GEE_THEY_ARE_ABSOLUTELY_IDENTICAL);
188
 
}
189
 
 
190
 
 
191
 
/* update a document entry */
192
 
 
193
 
int _mi_ft_update(MI_INFO *info, uint keynr, uchar *keybuf,
194
 
                  const uchar *oldrec, const uchar *newrec, my_off_t pos)
195
 
{
196
 
  int error= -1;
197
 
  FT_WORD *oldlist,*newlist, *old_word, *new_word;
198
 
  CHARSET_INFO *cs=info->s->keyinfo[keynr].seg->charset;
199
 
  uint key_length;
200
 
  int cmp, cmp2;
201
 
  DBUG_ENTER("_mi_ft_update");
202
 
 
203
 
  if (!(old_word=oldlist=_mi_ft_parserecord(info, keynr, oldrec,
204
 
                                            &info->ft_memroot)) ||
205
 
      !(new_word=newlist=_mi_ft_parserecord(info, keynr, newrec,
206
 
                                            &info->ft_memroot)))
207
 
    goto err;
208
 
 
209
 
  error=0;
210
 
  while(old_word->pos && new_word->pos)
211
 
  {
212
 
    cmp= ha_compare_text(cs, (uchar*) old_word->pos,old_word->len,
213
 
                             (uchar*) new_word->pos,new_word->len,0,0);
214
 
    cmp2= cmp ? 0 : (fabs(old_word->weight - new_word->weight) > 1.e-5);
215
 
 
216
 
    if (cmp < 0 || cmp2)
217
 
    {
218
 
      key_length=_ft_make_key(info,keynr,keybuf,old_word,pos);
219
 
      if ((error=_mi_ck_delete(info,keynr,(uchar*) keybuf,key_length)))
220
 
        goto err;
221
 
    }
222
 
    if (cmp > 0 || cmp2)
223
 
    {
224
 
      key_length=_ft_make_key(info,keynr,keybuf,new_word,pos);
225
 
      if ((error=_mi_ck_write(info,keynr,(uchar*) keybuf,key_length)))
226
 
        goto err;
227
 
    }
228
 
    if (cmp<=0) old_word++;
229
 
    if (cmp>=0) new_word++;
230
 
 }
231
 
 if (old_word->pos)
232
 
   error=_mi_ft_erase(info,keynr,keybuf,old_word,pos);
233
 
 else if (new_word->pos)
234
 
   error=_mi_ft_store(info,keynr,keybuf,new_word,pos);
235
 
 
236
 
err:
237
 
  free_root(&info->ft_memroot, MYF(MY_MARK_BLOCKS_FREE));
238
 
  DBUG_RETURN(error);
239
 
}
240
 
 
241
 
 
242
 
/* adds a document to the collection */
243
 
 
244
 
int _mi_ft_add(MI_INFO *info, uint keynr, uchar *keybuf, const uchar *record,
245
 
               my_off_t pos)
246
 
{
247
 
  int error= -1;
248
 
  FT_WORD *wlist;
249
 
  DBUG_ENTER("_mi_ft_add");
250
 
  DBUG_PRINT("enter",("keynr: %d",keynr));
251
 
 
252
 
  if ((wlist=_mi_ft_parserecord(info, keynr, record, &info->ft_memroot)))
253
 
    error=_mi_ft_store(info,keynr,keybuf,wlist,pos);
254
 
 
255
 
  free_root(&info->ft_memroot, MYF(MY_MARK_BLOCKS_FREE));
256
 
  DBUG_PRINT("exit",("Return: %d",error));
257
 
  DBUG_RETURN(error);
258
 
}
259
 
 
260
 
 
261
 
/* removes a document from the collection */
262
 
 
263
 
int _mi_ft_del(MI_INFO *info, uint keynr, uchar *keybuf, const uchar *record,
264
 
               my_off_t pos)
265
 
{
266
 
  int error= -1;
267
 
  FT_WORD *wlist;
268
 
  DBUG_ENTER("_mi_ft_del");
269
 
  DBUG_PRINT("enter",("keynr: %d",keynr));
270
 
 
271
 
  if ((wlist=_mi_ft_parserecord(info, keynr, record, &info->ft_memroot)))
272
 
    error=_mi_ft_erase(info,keynr,keybuf,wlist,pos);
273
 
 
274
 
  free_root(&info->ft_memroot, MYF(MY_MARK_BLOCKS_FREE));
275
 
  DBUG_PRINT("exit",("Return: %d",error));
276
 
  DBUG_RETURN(error);
277
 
}
278
 
 
279
 
uint _ft_make_key(MI_INFO *info, uint keynr, uchar *keybuf, FT_WORD *wptr,
280
 
                  my_off_t filepos)
281
 
{
282
 
  uchar buf[HA_FT_MAXBYTELEN+16];
283
 
  DBUG_ENTER("_ft_make_key");
284
 
 
285
 
#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
286
 
  {
287
 
    float weight=(float) ((filepos==HA_OFFSET_ERROR) ? 0 : wptr->weight);
288
 
    mi_float4store(buf,weight);
289
 
  }
290
 
#else
291
 
#error
292
 
#endif
293
 
 
294
 
  int2store(buf+HA_FT_WLEN,wptr->len);
295
 
  memcpy(buf+HA_FT_WLEN+2,wptr->pos,wptr->len);
296
 
  DBUG_RETURN(_mi_make_key(info,keynr,(uchar*) keybuf,buf,filepos));
297
 
}
298
 
 
299
 
 
300
 
/*
301
 
  convert key value to ft2
302
 
*/
303
 
 
304
 
uint _mi_ft_convert_to_ft2(MI_INFO *info, uint keynr, uchar *key)
305
 
{
306
 
  my_off_t root;
307
 
  DYNAMIC_ARRAY *da=info->ft1_to_ft2;
308
 
  MI_KEYDEF *keyinfo=&info->s->ft2_keyinfo;
309
 
  uchar *key_ptr= (uchar*) dynamic_array_ptr(da, 0), *end;
310
 
  uint length, key_length;
311
 
  DBUG_ENTER("_mi_ft_convert_to_ft2");
312
 
 
313
 
  /* we'll generate one pageful at once, and insert the rest one-by-one */
314
 
  /* calculating the length of this page ...*/
315
 
  length=(keyinfo->block_length-2) / keyinfo->keylength;
316
 
  set_if_smaller(length, da->elements);
317
 
  length=length * keyinfo->keylength;
318
 
 
319
 
  get_key_full_length_rdonly(key_length, key);
320
 
  while (_mi_ck_delete(info, keynr, key, key_length) == 0)
321
 
  {
322
 
    /*
323
 
      nothing to do here.
324
 
      _mi_ck_delete() will populate info->ft1_to_ft2 with deleted keys
325
 
     */
326
 
  }
327
 
 
328
 
  /* creating pageful of keys */
329
 
  mi_putint(info->buff,length+2,0);
330
 
  memcpy(info->buff+2, key_ptr, length);
331
 
  info->buff_used=info->page_changed=1;           /* info->buff is used */
332
 
  if ((root= _mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR ||
333
 
      _mi_write_keypage(info,keyinfo,root,DFLT_INIT_HITS,info->buff))
334
 
    DBUG_RETURN(-1);
335
 
 
336
 
  /* inserting the rest of key values */
337
 
  end= (uchar*) dynamic_array_ptr(da, da->elements);
338
 
  for (key_ptr+=length; key_ptr < end; key_ptr+=keyinfo->keylength)
339
 
    if(_mi_ck_real_write_btree(info, keyinfo, key_ptr, 0, &root, SEARCH_SAME))
340
 
      DBUG_RETURN(-1);
341
 
 
342
 
  /* now, writing the word key entry */
343
 
  ft_intXstore(key+key_length, - (int) da->elements);
344
 
  _mi_dpointer(info, key+key_length+HA_FT_WLEN, root);
345
 
 
346
 
  DBUG_RETURN(_mi_ck_real_write_btree(info,
347
 
                                     info->s->keyinfo+keynr,
348
 
                                     key, 0,
349
 
                                     &info->s->state.key_root[keynr],
350
 
                                     SEARCH_SAME));
351
 
}
352