~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to storage/myisam/mi_key.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

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
  reg1 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
 
 
242
    keypart_map>>= 1;
 
243
    if (keyseg->null_bit)
 
244
    {
 
245
      if (!(*key++= (char) 1-*old++))                   /* Copy null marker */
 
246
      {
 
247
        if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
 
248
          old+= 2;
 
249
        continue;                                       /* Found NULL */
 
250
      }
 
251
    }
 
252
    char_length= (!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length;
 
253
    pos=old;
 
254
    if (keyseg->flag & HA_SPACE_PACK)
 
255
    {
 
256
      uchar *end=pos+length;
 
257
      if (type == HA_KEYTYPE_NUM)
 
258
      {
 
259
        while (pos < end && pos[0] == ' ')
 
260
          pos++;
 
261
      }
 
262
      else if (type != HA_KEYTYPE_BINARY)
 
263
      {
 
264
        while (end > pos && end[-1] == ' ')
 
265
          end--;
 
266
      }
 
267
      length=(uint) (end-pos);
 
268
      FIX_LENGTH(cs, pos, length, char_length);
 
269
      store_key_length_inc(key,char_length);
 
270
      memcpy((uchar*) key,pos,(size_t) char_length);
 
271
      key+= char_length;
 
272
      continue;
 
273
    }
 
274
    else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
 
275
    {
 
276
      /* Length of key-part used with mi_rkey() always 2 */
 
277
      uint tmp_length=uint2korr(pos);
 
278
      pos+=2;
 
279
      set_if_smaller(length,tmp_length);        /* Safety */
 
280
      FIX_LENGTH(cs, pos, length, char_length);
 
281
      store_key_length_inc(key,char_length);
 
282
      old+=2;                                   /* Skip length */
 
283
      memcpy((uchar*) key, pos,(size_t) char_length);
 
284
      key+= char_length;
 
285
      continue;
 
286
    }
 
287
    else if (keyseg->flag & HA_SWAP_KEY)
 
288
    {                                           /* Numerical column */
 
289
      pos+=length;
 
290
      while (length--)
 
291
        *key++ = *--pos;
 
292
      continue;
 
293
    }
 
294
    FIX_LENGTH(cs, pos, length, char_length);
 
295
    memcpy((uchar*) key, pos, char_length);
 
296
    if (length > char_length)
 
297
      cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
 
298
    key+= length;
 
299
  }
 
300
  if (last_used_keyseg)
 
301
    *last_used_keyseg= keyseg;
 
302
 
 
303
  DBUG_RETURN((uint) (key-start_key));
 
304
} /* _mi_pack_key */
 
305
 
 
306
 
 
307
 
 
308
/*
 
309
  Store found key in record
 
310
 
 
311
  SYNOPSIS
 
312
    _mi_put_key_in_record()
 
313
    info                MyISAM handler
 
314
    keynr               Key number that was used
 
315
    record              Store key here
 
316
 
 
317
    Last read key is in info->lastkey
 
318
 
 
319
 NOTES
 
320
   Used when only-keyread is wanted
 
321
 
 
322
 RETURN
 
323
   0   ok
 
324
   1   error
 
325
*/
 
326
 
 
327
static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
 
328
                                 uchar *record)
 
329
{
 
330
  reg2 uchar *key;
 
331
  uchar *pos,*key_end;
 
332
  reg1 HA_KEYSEG *keyseg;
 
333
  uchar *blob_ptr;
 
334
  DBUG_ENTER("_mi_put_key_in_record");
 
335
 
 
336
  blob_ptr= (uchar*) info->lastkey2;             /* Place to put blob parts */
 
337
  key=(uchar*) info->lastkey;                    /* KEy that was read */
 
338
  key_end=key+info->lastkey_length;
 
339
  for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
 
340
  {
 
341
    if (keyseg->null_bit)
 
342
    {
 
343
      if (!*key++)
 
344
      {
 
345
        record[keyseg->null_pos]|= keyseg->null_bit;
 
346
        continue;
 
347
      }
 
348
      record[keyseg->null_pos]&= ~keyseg->null_bit;
 
349
    }
 
350
    if (keyseg->type == HA_KEYTYPE_BIT)
 
351
    {
 
352
      uint length= keyseg->length;
 
353
 
 
354
      if (keyseg->bit_length)
 
355
      {
 
356
        uchar bits= *key++;
 
357
        set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start,
 
358
                     keyseg->bit_length);
 
359
        length--;
 
360
      }
 
361
      else
 
362
      {
 
363
        clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start,
 
364
                     keyseg->bit_length);
 
365
      }
 
366
      memcpy(record + keyseg->start, (uchar*) key, length);
 
367
      key+= length;
 
368
      continue;
 
369
    }
 
370
    if (keyseg->flag & HA_SPACE_PACK)
 
371
    {
 
372
      uint length;
 
373
      get_key_length(length,key);
 
374
#ifdef CHECK_KEYS
 
375
      if (length > keyseg->length || key+length > key_end)
 
376
        goto err;
 
377
#endif
 
378
      pos= record+keyseg->start;
 
379
      if (keyseg->type != (int) HA_KEYTYPE_NUM)
 
380
      {
 
381
        memcpy(pos,key,(size_t) length);
 
382
        keyseg->charset->cset->fill(keyseg->charset,
 
383
                                    (char*) pos + length,
 
384
                                    keyseg->length - length,
 
385
                                    ' ');
 
386
      }
 
387
      else
 
388
      {
 
389
        bfill(pos,keyseg->length-length,' ');
 
390
        memcpy(pos+keyseg->length-length,key,(size_t) length);
 
391
      }
 
392
      key+=length;
 
393
      continue;
 
394
    }
 
395
 
 
396
    if (keyseg->flag & HA_VAR_LENGTH_PART)
 
397
    {
 
398
      uint length;
 
399
      get_key_length(length,key);
 
400
#ifdef CHECK_KEYS
 
401
      if (length > keyseg->length || key+length > key_end)
 
402
        goto err;
 
403
#endif
 
404
      /* Store key length */
 
405
      if (keyseg->bit_start == 1)
 
406
        *(uchar*) (record+keyseg->start)= (uchar) length;
 
407
      else
 
408
        int2store(record+keyseg->start, length);
 
409
      /* And key data */
 
410
      memcpy(record+keyseg->start + keyseg->bit_start, (uchar*) key, length);
 
411
      key+= length;
 
412
    }
 
413
    else if (keyseg->flag & HA_BLOB_PART)
 
414
    {
 
415
      uint length;
 
416
      get_key_length(length,key);
 
417
#ifdef CHECK_KEYS
 
418
      if (length > keyseg->length || key+length > key_end)
 
419
        goto err;
 
420
#endif
 
421
      memcpy(record+keyseg->start+keyseg->bit_start,
 
422
             (char*) &blob_ptr,sizeof(char*));
 
423
      memcpy(blob_ptr,key,length);
 
424
      blob_ptr+=length;
 
425
 
 
426
      /* The above changed info->lastkey2. Inform mi_rnext_same(). */
 
427
      info->update&= ~HA_STATE_RNEXT_SAME;
 
428
 
 
429
      _my_store_blob_length(record+keyseg->start,
 
430
                            (uint) keyseg->bit_start,length);
 
431
      key+=length;
 
432
    }
 
433
    else if (keyseg->flag & HA_SWAP_KEY)
 
434
    {
 
435
      uchar *to=  record+keyseg->start+keyseg->length;
 
436
      uchar *end= key+keyseg->length;
 
437
#ifdef CHECK_KEYS
 
438
      if (end > key_end)
 
439
        goto err;
 
440
#endif
 
441
      do
 
442
      {
 
443
         *--to= *key++;
 
444
      } while (key != end);
 
445
      continue;
 
446
    }
 
447
    else
 
448
    {
 
449
#ifdef CHECK_KEYS
 
450
      if (key+keyseg->length > key_end)
 
451
        goto err;
 
452
#endif
 
453
      memcpy(record+keyseg->start,(uchar*) key,
 
454
             (size_t) keyseg->length);
 
455
      key+= keyseg->length;
 
456
    }
 
457
  }
 
458
  DBUG_RETURN(0);
 
459
 
 
460
err:
 
461
  DBUG_RETURN(1);                               /* Crashed row */
 
462
} /* _mi_put_key_in_record */
 
463
 
 
464
 
 
465
        /* Here when key reads are used */
 
466
 
 
467
int _mi_read_key_record(MI_INFO *info, my_off_t filepos, uchar *buf)
 
468
{
 
469
  fast_mi_writeinfo(info);
 
470
  if (filepos != HA_OFFSET_ERROR)
 
471
  {
 
472
    if (info->lastinx >= 0)
 
473
    {                           /* Read only key */
 
474
      if (_mi_put_key_in_record(info,(uint) info->lastinx,buf))
 
475
      {
 
476
        mi_print_error(info->s, HA_ERR_CRASHED);
 
477
        my_errno=HA_ERR_CRASHED;
 
478
        return -1;
 
479
      }
 
480
      info->update|= HA_STATE_AKTIV; /* We should find a record */
 
481
      return 0;
 
482
    }
 
483
    my_errno=HA_ERR_WRONG_INDEX;
 
484
  }
 
485
  return(-1);                           /* Wrong data to read */
 
486
}
 
487
 
 
488
 
 
489
/*
 
490
  Retrieve auto_increment info
 
491
 
 
492
  SYNOPSIS
 
493
    retrieve_auto_increment()
 
494
    info                        MyISAM handler
 
495
    record                      Row to update
 
496
 
 
497
  IMPLEMENTATION
 
498
    For signed columns we don't retrieve the auto increment value if it's
 
499
    less than zero.
 
500
*/
 
501
 
 
502
ulonglong retrieve_auto_increment(MI_INFO *info,const uchar *record)
 
503
{
 
504
  ulonglong value= 0;                   /* Store unsigned values here */
 
505
  longlong s_value= 0;                  /* Store signed values here */
 
506
  HA_KEYSEG *keyseg= info->s->keyinfo[info->s->base.auto_key-1].seg;
 
507
  const uchar *key= (uchar*) record + keyseg->start;
 
508
 
 
509
  switch (keyseg->type) {
 
510
  case HA_KEYTYPE_INT8:
 
511
    s_value= (longlong) *(char*)key;
 
512
    break;
 
513
  case HA_KEYTYPE_BINARY:
 
514
    value=(ulonglong)  *(uchar*) key;
 
515
    break;
 
516
  case HA_KEYTYPE_SHORT_INT:
 
517
    s_value= (longlong) sint2korr(key);
 
518
    break;
 
519
  case HA_KEYTYPE_USHORT_INT:
 
520
    value=(ulonglong) uint2korr(key);
 
521
    break;
 
522
  case HA_KEYTYPE_LONG_INT:
 
523
    s_value= (longlong) sint4korr(key);
 
524
    break;
 
525
  case HA_KEYTYPE_ULONG_INT:
 
526
    value=(ulonglong) uint4korr(key);
 
527
    break;
 
528
  case HA_KEYTYPE_INT24:
 
529
    s_value= (longlong) sint3korr(key);
 
530
    break;
 
531
  case HA_KEYTYPE_UINT24:
 
532
    value=(ulonglong) uint3korr(key);
 
533
    break;
 
534
  case HA_KEYTYPE_FLOAT:                        /* This shouldn't be used */
 
535
  {
 
536
    float f_1;
 
537
    float4get(f_1,key);
 
538
    /* Ignore negative values */
 
539
    value = (f_1 < (float) 0.0) ? 0 : (ulonglong) f_1;
 
540
    break;
 
541
  }
 
542
  case HA_KEYTYPE_DOUBLE:                       /* This shouldn't be used */
 
543
  {
 
544
    double f_1;
 
545
    float8get(f_1,key);
 
546
    /* Ignore negative values */
 
547
    value = (f_1 < 0.0) ? 0 : (ulonglong) f_1;
 
548
    break;
 
549
  }
 
550
  case HA_KEYTYPE_LONGLONG:
 
551
    s_value= sint8korr(key);
 
552
    break;
 
553
  case HA_KEYTYPE_ULONGLONG:
 
554
    value= uint8korr(key);
 
555
    break;
 
556
  default:
 
557
    DBUG_ASSERT(0);
 
558
    value=0;                                    /* Error */
 
559
    break;
 
560
  }
 
561
 
 
562
  /*
 
563
    The following code works becasue if s_value < 0 then value is 0
 
564
    and if s_value == 0 then value will contain either s_value or the
 
565
    correct value.
 
566
  */
 
567
  return (s_value > 0) ? (ulonglong) s_value : value;
 
568
}