~skinny.moey/drizzle/branch-rev

« back to all changes in this revision

Viewing changes to storage/myisam/mi_key.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-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
/* Functions to handle keys */
 
17
 
 
18
#include "myisamdef.h"
 
19
#include "m_ctype.h"
 
20
#include "sp_defs.h"
 
21
#ifdef HAVE_IEEEFP_H
 
22
#include <ieeefp.h>
 
23
#endif
 
24
 
 
25
#define CHECK_KEYS                              /* Enable safety checks */
 
26
 
 
27
#define FIX_LENGTH(cs, pos, length, char_length)                            \
 
28
            do {                                                            \
 
29
              if (length > char_length)                                     \
 
30
                char_length= my_charpos(cs, pos, pos+length, char_length);  \
 
31
              set_if_smaller(char_length,length);                           \
 
32
            } while(0)
 
33
 
 
34
static int _mi_put_key_in_record(MI_INFO *info,uint keynr,uchar *record);
 
35
 
 
36
/*
 
37
  Make a intern key from a record
 
38
 
 
39
  SYNOPSIS
 
40
    _mi_make_key()
 
41
    info                MyiSAM handler
 
42
    keynr               key number
 
43
    key                 Store created key here
 
44
    record              Record
 
45
    filepos             Position to record in the data file
 
46
 
 
47
  RETURN
 
48
    Length of key
 
49
*/
 
50
 
 
51
uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
 
52
                  const uchar *record, my_off_t filepos)
 
53
{
 
54
  uchar *pos;
 
55
  uchar *start;
 
56
  register HA_KEYSEG *keyseg;
 
57
  my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT;
 
58
  DBUG_ENTER("_mi_make_key");
 
59
 
 
60
  if (info->s->keyinfo[keynr].flag & HA_SPATIAL)
 
61
  {
 
62
    /*
 
63
      TODO: nulls processing
 
64
    */
 
65
#ifdef HAVE_SPATIAL
 
66
    DBUG_RETURN(sp_make_key(info,keynr,key,record,filepos));
 
67
#else
 
68
    DBUG_ASSERT(0); /* mi_open should check that this never happens*/
 
69
#endif
 
70
  }
 
71
 
 
72
  start=key;
 
73
  for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
 
74
  {
 
75
    enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
 
76
    uint length=keyseg->length;
 
77
    uint char_length;
 
78
    CHARSET_INFO *cs=keyseg->charset;
 
79
 
 
80
    if (keyseg->null_bit)
 
81
    {
 
82
      if (record[keyseg->null_pos] & keyseg->null_bit)
 
83
      {
 
84
        *key++= 0;                              /* NULL in key */
 
85
        continue;
 
86
      }
 
87
      *key++=1;                                 /* Not NULL */
 
88
    }
 
89
 
 
90
    char_length= ((!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen :
 
91
                  length);
 
92
 
 
93
    pos= (uchar*) record+keyseg->start;
 
94
    if (type == HA_KEYTYPE_BIT)
 
95
    {
 
96
      if (keyseg->bit_length)
 
97
      {
 
98
        uchar bits= get_rec_bits((uchar*) record + keyseg->bit_pos,
 
99
                                 keyseg->bit_start, keyseg->bit_length);
 
100
        *key++= bits;
 
101
        length--;
 
102
      }
 
103
      memcpy((uchar*) key, pos, length);
 
104
      key+= length;
 
105
      continue;
 
106
    }
 
107
    if (keyseg->flag & HA_SPACE_PACK)
 
108
    {
 
109
      if (type != HA_KEYTYPE_NUM)
 
110
      {
 
111
        length= cs->cset->lengthsp(cs, (char*) pos, length);
 
112
      }
 
113
      else
 
114
      {
 
115
        uchar *end= pos + length;
 
116
        while (pos < end && pos[0] == ' ')
 
117
          pos++;
 
118
        length=(uint) (end-pos);
 
119
      }
 
120
      FIX_LENGTH(cs, pos, length, char_length);
 
121
      store_key_length_inc(key,char_length);
 
122
      memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
 
123
      key+=char_length;
 
124
      continue;
 
125
    }
 
126
    if (keyseg->flag & HA_VAR_LENGTH_PART)
 
127
    {
 
128
      uint pack_length= (keyseg->bit_start == 1 ? 1 : 2);
 
129
      uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
 
130
                        uint2korr(pos));
 
131
      pos+= pack_length;                        /* Skip VARCHAR length */
 
132
      set_if_smaller(length,tmp_length);
 
133
      FIX_LENGTH(cs, pos, length, char_length);
 
134
      store_key_length_inc(key,char_length);
 
135
      memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
 
136
      key+= char_length;
 
137
      continue;
 
138
    }
 
139
    else if (keyseg->flag & HA_BLOB_PART)
 
140
    {
 
141
      uint tmp_length=_mi_calc_blob_length(keyseg->bit_start,pos);
 
142
      memcpy_fixed((uchar*) &pos,pos+keyseg->bit_start,sizeof(char*));
 
143
      set_if_smaller(length,tmp_length);
 
144
      FIX_LENGTH(cs, pos, length, char_length);
 
145
      store_key_length_inc(key,char_length);
 
146
      memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
 
147
      key+= char_length;
 
148
      continue;
 
149
    }
 
150
    else if (keyseg->flag & HA_SWAP_KEY)
 
151
    {                                           /* Numerical column */
 
152
#ifdef HAVE_ISNAN
 
153
      if (type == HA_KEYTYPE_FLOAT)
 
154
      {
 
155
        float nr;
 
156
        float4get(nr,pos);
 
157
        if (isnan(nr))
 
158
        {
 
159
          /* Replace NAN with zero */
 
160
          bzero(key,length);
 
161
          key+=length;
 
162
          continue;
 
163
        }
 
164
      }
 
165
      else if (type == HA_KEYTYPE_DOUBLE)
 
166
      {
 
167
        double nr;
 
168
        float8get(nr,pos);
 
169
        if (isnan(nr))
 
170
        {
 
171
          bzero(key,length);
 
172
          key+=length;
 
173
          continue;
 
174
        }
 
175
      }
 
176
#endif
 
177
      pos+=length;
 
178
      while (length--)
 
179
      {
 
180
        *key++ = *--pos;
 
181
      }
 
182
      continue;
 
183
    }
 
184
    FIX_LENGTH(cs, pos, length, char_length);
 
185
    memcpy((uchar*) key, pos, char_length);
 
186
    if (length > char_length)
 
187
      cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
 
188
    key+= length;
 
189
  }
 
190
  _mi_dpointer(info,key,filepos);
 
191
  DBUG_PRINT("exit",("keynr: %d",keynr));
 
192
  DBUG_DUMP("key",(uchar*) start,(uint) (key-start)+keyseg->length);
 
193
  DBUG_EXECUTE("key",
 
194
               _mi_print_key(DBUG_FILE,info->s->keyinfo[keynr].seg,start,
 
195
                             (uint) (key-start)););
 
196
  DBUG_RETURN((uint) (key-start));              /* Return keylength */
 
197
} /* _mi_make_key */
 
198
 
 
199
 
 
200
/*
 
201
  Pack a key to intern format from given format (c_rkey)
 
202
 
 
203
  SYNOPSIS
 
204
    _mi_pack_key()
 
205
    info                MyISAM handler
 
206
    uint keynr          key number
 
207
    key                 Store packed key here
 
208
    old                 Not packed key
 
209
    keypart_map         bitmap of used keyparts
 
210
    last_used_keyseg    out parameter.  May be NULL
 
211
 
 
212
   RETURN
 
213
     length of packed key
 
214
 
 
215
     last_use_keyseg    Store pointer to the keyseg after the last used one
 
216
*/
 
217
 
 
218
uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old,
 
219
                  key_part_map keypart_map, HA_KEYSEG **last_used_keyseg)
 
220
{
 
221
  uchar *start_key=key;
 
222
  HA_KEYSEG *keyseg;
 
223
  my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT;
 
224
  DBUG_ENTER("_mi_pack_key");
 
225
 
 
226
  /* "one part" rtree key is 2*SPDIMS part key in MyISAM */
 
227
  if (info->s->keyinfo[keynr].key_alg == HA_KEY_ALG_RTREE)
 
228
    keypart_map= (((key_part_map)1) << (2*SPDIMS)) - 1;
 
229
 
 
230
  /* only key prefixes are supported */
 
231
  DBUG_ASSERT(((keypart_map+1) & keypart_map) == 0);
 
232
 
 
233
  for (keyseg= info->s->keyinfo[keynr].seg ; keyseg->type && keypart_map;
 
234
       old+= keyseg->length, keyseg++)
 
235
  {
 
236
    enum ha_base_keytype type= (enum ha_base_keytype) keyseg->type;
 
237
    uint length= keyseg->length;
 
238
    uint char_length;
 
239
    uchar *pos;
 
240
    CHARSET_INFO *cs=keyseg->charset;
 
241
    keypart_map>>= 1;
 
242
    if (keyseg->null_bit)
 
243
    {
 
244
      if (!(*key++= (char) 1-*old++))                   /* Copy null marker */
 
245
      {
 
246
        if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
 
247
          old+= 2;
 
248
        continue;                                       /* Found NULL */
 
249
      }
 
250
    }
 
251
    char_length= (!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length;
 
252
    pos=old;
 
253
    if (keyseg->flag & HA_SPACE_PACK)
 
254
    {
 
255
      uchar *end=pos+length;
 
256
      if (type == HA_KEYTYPE_NUM)
 
257
      {
 
258
        while (pos < end && pos[0] == ' ')
 
259
          pos++;
 
260
      }
 
261
      else if (type != HA_KEYTYPE_BINARY)
 
262
      {
 
263
        while (end > pos && end[-1] == ' ')
 
264
          end--;
 
265
      }
 
266
      length=(uint) (end-pos);
 
267
      FIX_LENGTH(cs, pos, length, char_length);
 
268
      store_key_length_inc(key,char_length);
 
269
      memcpy((uchar*) key,pos,(size_t) char_length);
 
270
      key+= char_length;
 
271
      continue;
 
272
    }
 
273
    else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
 
274
    {
 
275
      /* Length of key-part used with mi_rkey() always 2 */
 
276
      uint tmp_length=uint2korr(pos);
 
277
      pos+=2;
 
278
      set_if_smaller(length,tmp_length);        /* Safety */
 
279
      FIX_LENGTH(cs, pos, length, char_length);
 
280
      store_key_length_inc(key,char_length);
 
281
      old+=2;                                   /* Skip length */
 
282
      memcpy((uchar*) key, pos,(size_t) char_length);
 
283
      key+= char_length;
 
284
      continue;
 
285
    }
 
286
    else if (keyseg->flag & HA_SWAP_KEY)
 
287
    {                                           /* Numerical column */
 
288
      pos+=length;
 
289
      while (length--)
 
290
        *key++ = *--pos;
 
291
      continue;
 
292
    }
 
293
    FIX_LENGTH(cs, pos, length, char_length);
 
294
    memcpy((uchar*) key, pos, char_length);
 
295
    if (length > char_length)
 
296
      cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
 
297
    key+= length;
 
298
  }
 
299
  if (last_used_keyseg)
 
300
    *last_used_keyseg= keyseg;
 
301
 
 
302
  DBUG_RETURN((uint) (key-start_key));
 
303
} /* _mi_pack_key */
 
304
 
 
305
 
 
306
 
 
307
/*
 
308
  Store found key in record
 
309
 
 
310
  SYNOPSIS
 
311
    _mi_put_key_in_record()
 
312
    info                MyISAM handler
 
313
    keynr               Key number that was used
 
314
    record              Store key here
 
315
 
 
316
    Last read key is in info->lastkey
 
317
 
 
318
 NOTES
 
319
   Used when only-keyread is wanted
 
320
 
 
321
 RETURN
 
322
   0   ok
 
323
   1   error
 
324
*/
 
325
 
 
326
static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
 
327
                                 uchar *record)
 
328
{
 
329
  register uchar *key;
 
330
  uchar *pos,*key_end;
 
331
  register HA_KEYSEG *keyseg;
 
332
  uchar *blob_ptr;
 
333
  DBUG_ENTER("_mi_put_key_in_record");
 
334
 
 
335
  blob_ptr= (uchar*) info->lastkey2;             /* Place to put blob parts */
 
336
  key=(uchar*) info->lastkey;                    /* KEy that was read */
 
337
  key_end=key+info->lastkey_length;
 
338
  for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
 
339
  {
 
340
    if (keyseg->null_bit)
 
341
    {
 
342
      if (!*key++)
 
343
      {
 
344
        record[keyseg->null_pos]|= keyseg->null_bit;
 
345
        continue;
 
346
      }
 
347
      record[keyseg->null_pos]&= ~keyseg->null_bit;
 
348
    }
 
349
    if (keyseg->type == HA_KEYTYPE_BIT)
 
350
    {
 
351
      uint length= keyseg->length;
 
352
 
 
353
      if (keyseg->bit_length)
 
354
      {
 
355
        uchar bits= *key++;
 
356
        set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start,
 
357
                     keyseg->bit_length);
 
358
        length--;
 
359
      }
 
360
      else
 
361
      {
 
362
        clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start,
 
363
                     keyseg->bit_length);
 
364
      }
 
365
      memcpy(record + keyseg->start, (uchar*) key, length);
 
366
      key+= length;
 
367
      continue;
 
368
    }
 
369
    if (keyseg->flag & HA_SPACE_PACK)
 
370
    {
 
371
      uint length;
 
372
      get_key_length(length,key);
 
373
#ifdef CHECK_KEYS
 
374
      if (length > keyseg->length || key+length > key_end)
 
375
        goto err;
 
376
#endif
 
377
      pos= record+keyseg->start;
 
378
      if (keyseg->type != (int) HA_KEYTYPE_NUM)
 
379
      {
 
380
        memcpy(pos,key,(size_t) length);
 
381
        keyseg->charset->cset->fill(keyseg->charset,
 
382
                                    (char*) pos + length,
 
383
                                    keyseg->length - length,
 
384
                                    ' ');
 
385
      }
 
386
      else
 
387
      {
 
388
        bfill(pos,keyseg->length-length,' ');
 
389
        memcpy(pos+keyseg->length-length,key,(size_t) length);
 
390
      }
 
391
      key+=length;
 
392
      continue;
 
393
    }
 
394
 
 
395
    if (keyseg->flag & HA_VAR_LENGTH_PART)
 
396
    {
 
397
      uint length;
 
398
      get_key_length(length,key);
 
399
#ifdef CHECK_KEYS
 
400
      if (length > keyseg->length || key+length > key_end)
 
401
        goto err;
 
402
#endif
 
403
      /* Store key length */
 
404
      if (keyseg->bit_start == 1)
 
405
        *(uchar*) (record+keyseg->start)= (uchar) length;
 
406
      else
 
407
        int2store(record+keyseg->start, length);
 
408
      /* And key data */
 
409
      memcpy(record+keyseg->start + keyseg->bit_start, (uchar*) key, length);
 
410
      key+= length;
 
411
    }
 
412
    else if (keyseg->flag & HA_BLOB_PART)
 
413
    {
 
414
      uint length;
 
415
      get_key_length(length,key);
 
416
#ifdef CHECK_KEYS
 
417
      if (length > keyseg->length || key+length > key_end)
 
418
        goto err;
 
419
#endif
 
420
      memcpy(record+keyseg->start+keyseg->bit_start,
 
421
             (char*) &blob_ptr,sizeof(char*));
 
422
      memcpy(blob_ptr,key,length);
 
423
      blob_ptr+=length;
 
424
 
 
425
      /* The above changed info->lastkey2. Inform mi_rnext_same(). */
 
426
      info->update&= ~HA_STATE_RNEXT_SAME;
 
427
 
 
428
      _my_store_blob_length(record+keyseg->start,
 
429
                            (uint) keyseg->bit_start,length);
 
430
      key+=length;
 
431
    }
 
432
    else if (keyseg->flag & HA_SWAP_KEY)
 
433
    {
 
434
      uchar *to=  record+keyseg->start+keyseg->length;
 
435
      uchar *end= key+keyseg->length;
 
436
#ifdef CHECK_KEYS
 
437
      if (end > key_end)
 
438
        goto err;
 
439
#endif
 
440
      do
 
441
      {
 
442
         *--to= *key++;
 
443
      } while (key != end);
 
444
      continue;
 
445
    }
 
446
    else
 
447
    {
 
448
#ifdef CHECK_KEYS
 
449
      if (key+keyseg->length > key_end)
 
450
        goto err;
 
451
#endif
 
452
      memcpy(record+keyseg->start,(uchar*) key,
 
453
             (size_t) keyseg->length);
 
454
      key+= keyseg->length;
 
455
    }
 
456
  }
 
457
  DBUG_RETURN(0);
 
458
 
 
459
err:
 
460
  DBUG_RETURN(1);                               /* Crashed row */
 
461
} /* _mi_put_key_in_record */
 
462
 
 
463
 
 
464
        /* Here when key reads are used */
 
465
 
 
466
int _mi_read_key_record(MI_INFO *info, my_off_t filepos, uchar *buf)
 
467
{
 
468
  fast_mi_writeinfo(info);
 
469
  if (filepos != HA_OFFSET_ERROR)
 
470
  {
 
471
    if (info->lastinx >= 0)
 
472
    {                           /* Read only key */
 
473
      if (_mi_put_key_in_record(info,(uint) info->lastinx,buf))
 
474
      {
 
475
        mi_print_error(info->s, HA_ERR_CRASHED);
 
476
        my_errno=HA_ERR_CRASHED;
 
477
        return -1;
 
478
      }
 
479
      info->update|= HA_STATE_AKTIV; /* We should find a record */
 
480
      return 0;
 
481
    }
 
482
    my_errno=HA_ERR_WRONG_INDEX;
 
483
  }
 
484
  return(-1);                           /* Wrong data to read */
 
485
}
 
486
 
 
487
 
 
488
/*
 
489
  Save current key tuple to record and call index condition check function
 
490
 
 
491
  SYNOPSIS
 
492
    mi_check_index_cond()
 
493
      info    MyISAM handler
 
494
      keynr   Index we're running a scan on
 
495
      record  Record buffer to use (it is assumed that index check function 
 
496
              will look for column values there)
 
497
 
 
498
  RETURN
 
499
    -1  Error 
 
500
    0   Index condition is not satisfied, continue scanning
 
501
    1   Index condition is satisfied
 
502
    2   Index condition is not satisfied, end the scan. 
 
503
*/
 
504
 
 
505
int mi_check_index_cond(register MI_INFO *info, uint keynr, uchar *record)
 
506
{
 
507
  if (_mi_put_key_in_record(info, keynr, record))
 
508
  {
 
509
    mi_print_error(info->s, HA_ERR_CRASHED);
 
510
    my_errno=HA_ERR_CRASHED;
 
511
    return -1;
 
512
  }
 
513
  return info->index_cond_func(info->index_cond_func_arg);
 
514
}
 
515
 
 
516
 
 
517
/*
 
518
  Retrieve auto_increment info
 
519
 
 
520
  SYNOPSIS
 
521
    retrieve_auto_increment()
 
522
    info                        MyISAM handler
 
523
    record                      Row to update
 
524
 
 
525
  IMPLEMENTATION
 
526
    For signed columns we don't retrieve the auto increment value if it's
 
527
    less than zero.
 
528
*/
 
529
 
 
530
ulonglong retrieve_auto_increment(MI_INFO *info,const uchar *record)
 
531
{
 
532
  ulonglong value= 0;                   /* Store unsigned values here */
 
533
  longlong s_value= 0;                  /* Store signed values here */
 
534
  HA_KEYSEG *keyseg= info->s->keyinfo[info->s->base.auto_key-1].seg;
 
535
  const uchar *key= (uchar*) record + keyseg->start;
 
536
 
 
537
  switch (keyseg->type) {
 
538
  case HA_KEYTYPE_INT8:
 
539
    s_value= (longlong) *(char*)key;
 
540
    break;
 
541
  case HA_KEYTYPE_BINARY:
 
542
    value=(ulonglong)  *(uchar*) key;
 
543
    break;
 
544
  case HA_KEYTYPE_SHORT_INT:
 
545
    s_value= (longlong) sint2korr(key);
 
546
    break;
 
547
  case HA_KEYTYPE_USHORT_INT:
 
548
    value=(ulonglong) uint2korr(key);
 
549
    break;
 
550
  case HA_KEYTYPE_LONG_INT:
 
551
    s_value= (longlong) sint4korr(key);
 
552
    break;
 
553
  case HA_KEYTYPE_ULONG_INT:
 
554
    value=(ulonglong) uint4korr(key);
 
555
    break;
 
556
  case HA_KEYTYPE_INT24:
 
557
    s_value= (longlong) sint3korr(key);
 
558
    break;
 
559
  case HA_KEYTYPE_UINT24:
 
560
    value=(ulonglong) uint3korr(key);
 
561
    break;
 
562
  case HA_KEYTYPE_FLOAT:                        /* This shouldn't be used */
 
563
  {
 
564
    float f_1;
 
565
    float4get(f_1,key);
 
566
    /* Ignore negative values */
 
567
    value = (f_1 < (float) 0.0) ? 0 : (ulonglong) f_1;
 
568
    break;
 
569
  }
 
570
  case HA_KEYTYPE_DOUBLE:                       /* This shouldn't be used */
 
571
  {
 
572
    double f_1;
 
573
    float8get(f_1,key);
 
574
    /* Ignore negative values */
 
575
    value = (f_1 < 0.0) ? 0 : (ulonglong) f_1;
 
576
    break;
 
577
  }
 
578
  case HA_KEYTYPE_LONGLONG:
 
579
    s_value= sint8korr(key);
 
580
    break;
 
581
  case HA_KEYTYPE_ULONGLONG:
 
582
    value= uint8korr(key);
 
583
    break;
 
584
  default:
 
585
    DBUG_ASSERT(0);
 
586
    value=0;                                    /* Error */
 
587
    break;
 
588
  }
 
589
 
 
590
  /*
 
591
    The following code works becasue if s_value < 0 then value is 0
 
592
    and if s_value == 0 then value will contain either s_value or the
 
593
    correct value.
 
594
  */
 
595
  return (s_value > 0) ? (ulonglong) s_value : value;
 
596
}