~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/myisam/mi_key.cc

Merge Stewarts cleanup for proto on tinyint

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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
15
 
 
16
 
/* Functions to handle keys */
17
 
 
18
 
#include "myisam_priv.h"
19
 
#include "drizzled/charset_info.h"
20
 
#ifdef HAVE_IEEEFP_H
21
 
#include <ieeefp.h>
22
 
#endif
23
 
#include <math.h>
24
 
#include <cassert>
25
 
 
26
 
using namespace drizzled;
27
 
using namespace std;
28
 
 
29
 
#define CHECK_KEYS                              /* Enable safety checks */
30
 
 
31
 
#define FIX_LENGTH(cs, pos, length, char_length)                            \
32
 
            do {                                                            \
33
 
              if (length > char_length)                                     \
34
 
                char_length= my_charpos(cs, pos, pos+length, char_length);  \
35
 
              drizzled::set_if_smaller(char_length,length);                           \
36
 
            } while(0)
37
 
 
38
 
static int _mi_put_key_in_record(MI_INFO *info,uint32_t keynr,unsigned char *record);
39
 
 
40
 
/*
41
 
  Make a intern key from a record
42
 
 
43
 
  SYNOPSIS
44
 
    _mi_make_key()
45
 
    info                MyiSAM handler
46
 
    keynr               key number
47
 
    key                 Store created key here
48
 
    record              Record
49
 
    filepos             Position to record in the data file
50
 
 
51
 
  RETURN
52
 
    Length of key
53
 
*/
54
 
 
55
 
uint32_t _mi_make_key(register MI_INFO *info, uint32_t keynr, unsigned char *key,
56
 
                      const unsigned char *record, drizzled::internal::my_off_t filepos)
57
 
{
58
 
  unsigned char *pos;
59
 
  unsigned char *start;
60
 
  register HA_KEYSEG *keyseg;
61
 
 
62
 
  start=key;
63
 
  for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
64
 
  {
65
 
    enum drizzled::ha_base_keytype type=(enum drizzled::ha_base_keytype) keyseg->type;
66
 
    uint32_t length=keyseg->length;
67
 
    uint32_t char_length;
68
 
    const drizzled::CHARSET_INFO * const cs=keyseg->charset;
69
 
 
70
 
    if (keyseg->null_bit)
71
 
    {
72
 
      if (record[keyseg->null_pos] & keyseg->null_bit)
73
 
      {
74
 
        *key++= 0;                              /* NULL in key */
75
 
        continue;
76
 
      }
77
 
      *key++=1;                                 /* Not NULL */
78
 
    }
79
 
 
80
 
    char_length= ((cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen :
81
 
                  length);
82
 
 
83
 
    pos= (unsigned char*) record+keyseg->start;
84
 
 
85
 
    if (keyseg->flag & HA_SPACE_PACK)
86
 
    {
87
 
      length= cs->cset->lengthsp(cs, (char*) pos, length);
88
 
 
89
 
      FIX_LENGTH(cs, pos, length, char_length);
90
 
      store_key_length_inc(key,char_length);
91
 
      memcpy(key, pos, char_length);
92
 
      key+=char_length;
93
 
      continue;
94
 
    }
95
 
    if (keyseg->flag & HA_VAR_LENGTH_PART)
96
 
    {
97
 
      uint32_t pack_length= (keyseg->bit_start == 1 ? 1 : 2);
98
 
      uint32_t tmp_length= (pack_length == 1 ? (uint) *(unsigned char*) pos :
99
 
                        uint2korr(pos));
100
 
      pos+= pack_length;                        /* Skip VARCHAR length */
101
 
      drizzled::set_if_smaller(length,tmp_length);
102
 
      FIX_LENGTH(cs, pos, length, char_length);
103
 
      store_key_length_inc(key,char_length);
104
 
      memcpy(key, pos, char_length);
105
 
      key+= char_length;
106
 
      continue;
107
 
    }
108
 
    else if (keyseg->flag & HA_BLOB_PART)
109
 
    {
110
 
      uint32_t tmp_length=_mi_calc_blob_length(keyseg->bit_start,pos);
111
 
      memcpy(&pos, pos+keyseg->bit_start, sizeof(char*));
112
 
      drizzled::set_if_smaller(length,tmp_length);
113
 
      FIX_LENGTH(cs, pos, length, char_length);
114
 
      store_key_length_inc(key,char_length);
115
 
      memcpy(key, pos, char_length);
116
 
      key+= char_length;
117
 
      continue;
118
 
    }
119
 
    else if (keyseg->flag & HA_SWAP_KEY)
120
 
    {                                           /* Numerical column */
121
 
      if (type == drizzled::HA_KEYTYPE_DOUBLE)
122
 
      {
123
 
        double nr;
124
 
        float8get(nr,pos);
125
 
        if (isnan(nr))
126
 
        {
127
 
          memset(key, 0, length);
128
 
          key+=length;
129
 
          continue;
130
 
        }
131
 
      }
132
 
      pos+=length;
133
 
      while (length--)
134
 
      {
135
 
        *key++ = *--pos;
136
 
      }
137
 
      continue;
138
 
    }
139
 
    FIX_LENGTH(cs, pos, length, char_length);
140
 
    memcpy(key, pos, char_length);
141
 
    if (length > char_length)
142
 
      cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
143
 
    key+= length;
144
 
  }
145
 
  _mi_dpointer(info,key,filepos);
146
 
  return((uint) (key-start));           /* Return keylength */
147
 
} /* _mi_make_key */
148
 
 
149
 
 
150
 
/*
151
 
  Pack a key to intern format from given format (c_rkey)
152
 
 
153
 
  SYNOPSIS
154
 
    _mi_pack_key()
155
 
    info                MyISAM handler
156
 
    uint32_t keynr              key number
157
 
    key                 Store packed key here
158
 
    old                 Not packed key
159
 
    keypart_map         bitmap of used keyparts
160
 
    last_used_keyseg    out parameter.  May be NULL
161
 
 
162
 
   RETURN
163
 
     length of packed key
164
 
 
165
 
     last_use_keyseg    Store pointer to the keyseg after the last used one
166
 
*/
167
 
 
168
 
uint32_t _mi_pack_key(register MI_INFO *info, uint32_t keynr, unsigned char *key, unsigned char *old,
169
 
                      drizzled::key_part_map keypart_map, HA_KEYSEG **last_used_keyseg)
170
 
{
171
 
  unsigned char *start_key=key;
172
 
  HA_KEYSEG *keyseg;
173
 
 
174
 
  /* only key prefixes are supported */
175
 
  assert(((keypart_map+1) & keypart_map) == 0);
176
 
 
177
 
  for (keyseg= info->s->keyinfo[keynr].seg ; keyseg->type && keypart_map;
178
 
       old+= keyseg->length, keyseg++)
179
 
  {
180
 
    enum drizzled::ha_base_keytype type= (enum drizzled::ha_base_keytype) keyseg->type;
181
 
    uint32_t length= keyseg->length;
182
 
    uint32_t char_length;
183
 
    unsigned char *pos;
184
 
    const drizzled::CHARSET_INFO * const cs=keyseg->charset;
185
 
    keypart_map>>= 1;
186
 
    if (keyseg->null_bit)
187
 
    {
188
 
      if (!(*key++= (char) 1-*old++))                   /* Copy null marker */
189
 
      {
190
 
        if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
191
 
          old+= 2;
192
 
        continue;                                       /* Found NULL */
193
 
      }
194
 
    }
195
 
    char_length= (cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length;
196
 
    pos=old;
197
 
    if (keyseg->flag & HA_SPACE_PACK)
198
 
    {
199
 
      unsigned char *end=pos+length;
200
 
 
201
 
      if (type != drizzled::HA_KEYTYPE_BINARY)
202
 
      {
203
 
        while (end > pos && end[-1] == ' ')
204
 
          end--;
205
 
      }
206
 
      length=(uint) (end-pos);
207
 
      FIX_LENGTH(cs, pos, length, char_length);
208
 
      store_key_length_inc(key,char_length);
209
 
      memcpy(key, pos, char_length);
210
 
      key+= char_length;
211
 
      continue;
212
 
    }
213
 
    else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
214
 
    {
215
 
      /* Length of key-part used with mi_rkey() always 2 */
216
 
      uint32_t tmp_length=uint2korr(pos);
217
 
      pos+=2;
218
 
      drizzled::set_if_smaller(length,tmp_length);      /* Safety */
219
 
      FIX_LENGTH(cs, pos, length, char_length);
220
 
      store_key_length_inc(key,char_length);
221
 
      old+=2;                                   /* Skip length */
222
 
      memcpy(key, pos, char_length);
223
 
      key+= char_length;
224
 
      continue;
225
 
    }
226
 
    else if (keyseg->flag & HA_SWAP_KEY)
227
 
    {                                           /* Numerical column */
228
 
      pos+=length;
229
 
      while (length--)
230
 
        *key++ = *--pos;
231
 
      continue;
232
 
    }
233
 
    FIX_LENGTH(cs, pos, length, char_length);
234
 
    memcpy(key, pos, char_length);
235
 
    if (length > char_length)
236
 
      cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
237
 
    key+= length;
238
 
  }
239
 
  if (last_used_keyseg)
240
 
    *last_used_keyseg= keyseg;
241
 
 
242
 
  return((uint) (key-start_key));
243
 
} /* _mi_pack_key */
244
 
 
245
 
 
246
 
 
247
 
/*
248
 
  Store found key in record
249
 
 
250
 
  SYNOPSIS
251
 
    _mi_put_key_in_record()
252
 
    info                MyISAM handler
253
 
    keynr               Key number that was used
254
 
    record              Store key here
255
 
 
256
 
    Last read key is in info->lastkey
257
 
 
258
 
 NOTES
259
 
   Used when only-keyread is wanted
260
 
 
261
 
 RETURN
262
 
   0   ok
263
 
   1   error
264
 
*/
265
 
 
266
 
static int _mi_put_key_in_record(register MI_INFO *info, uint32_t keynr,
267
 
                                 unsigned char *record)
268
 
{
269
 
  register unsigned char *key;
270
 
  unsigned char *pos,*key_end;
271
 
  register HA_KEYSEG *keyseg;
272
 
  unsigned char *blob_ptr;
273
 
 
274
 
  blob_ptr= (unsigned char*) info->lastkey2;             /* Place to put blob parts */
275
 
  key=(unsigned char*) info->lastkey;                    /* KEy that was read */
276
 
  key_end=key+info->lastkey_length;
277
 
  for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
278
 
  {
279
 
    if (keyseg->null_bit)
280
 
    {
281
 
      if (!*key++)
282
 
      {
283
 
        record[keyseg->null_pos]|= keyseg->null_bit;
284
 
        continue;
285
 
      }
286
 
      record[keyseg->null_pos]&= ~keyseg->null_bit;
287
 
    }
288
 
 
289
 
    if (keyseg->flag & HA_SPACE_PACK)
290
 
    {
291
 
      uint32_t length;
292
 
      get_key_length(length,key);
293
 
#ifdef CHECK_KEYS
294
 
      if (length > keyseg->length || key+length > key_end)
295
 
        goto err;
296
 
#endif
297
 
      pos= record+keyseg->start;
298
 
 
299
 
      memcpy(pos, key, length);
300
 
      keyseg->charset->cset->fill(keyseg->charset,
301
 
                                  (char*) pos + length,
302
 
                                  keyseg->length - length,
303
 
                                  ' ');
304
 
      key+=length;
305
 
      continue;
306
 
    }
307
 
 
308
 
    if (keyseg->flag & HA_VAR_LENGTH_PART)
309
 
    {
310
 
      uint32_t length;
311
 
      get_key_length(length,key);
312
 
#ifdef CHECK_KEYS
313
 
      if (length > keyseg->length || key+length > key_end)
314
 
        goto err;
315
 
#endif
316
 
      /* Store key length */
317
 
      if (keyseg->bit_start == 1)
318
 
        *(unsigned char*) (record+keyseg->start)= (unsigned char) length;
319
 
      else
320
 
        int2store(record+keyseg->start, length);
321
 
      /* And key data */
322
 
      memcpy(record+keyseg->start + keyseg->bit_start, key, length);
323
 
      key+= length;
324
 
    }
325
 
    else if (keyseg->flag & HA_BLOB_PART)
326
 
    {
327
 
      uint32_t length;
328
 
      get_key_length(length,key);
329
 
#ifdef CHECK_KEYS
330
 
      if (length > keyseg->length || key+length > key_end)
331
 
        goto err;
332
 
#endif
333
 
      memcpy(record+keyseg->start+keyseg->bit_start,
334
 
             &blob_ptr,sizeof(char*));
335
 
      memcpy(blob_ptr,key,length);
336
 
      blob_ptr+=length;
337
 
 
338
 
      /* The above changed info->lastkey2. Inform mi_rnext_same(). */
339
 
      info->update&= ~HA_STATE_RNEXT_SAME;
340
 
 
341
 
      _my_store_blob_length(record+keyseg->start,
342
 
                            (uint) keyseg->bit_start,length);
343
 
      key+=length;
344
 
    }
345
 
    else if (keyseg->flag & HA_SWAP_KEY)
346
 
    {
347
 
      unsigned char *to=  record+keyseg->start+keyseg->length;
348
 
      unsigned char *end= key+keyseg->length;
349
 
#ifdef CHECK_KEYS
350
 
      if (end > key_end)
351
 
        goto err;
352
 
#endif
353
 
      do
354
 
      {
355
 
         *--to= *key++;
356
 
      } while (key != end);
357
 
      continue;
358
 
    }
359
 
    else
360
 
    {
361
 
#ifdef CHECK_KEYS
362
 
      if (key+keyseg->length > key_end)
363
 
        goto err;
364
 
#endif
365
 
      memcpy(record+keyseg->start, key, keyseg->length);
366
 
      key+= keyseg->length;
367
 
    }
368
 
  }
369
 
  return(0);
370
 
 
371
 
err:
372
 
  return(1);                            /* Crashed row */
373
 
} /* _mi_put_key_in_record */
374
 
 
375
 
 
376
 
        /* Here when key reads are used */
377
 
 
378
 
int _mi_read_key_record(MI_INFO *info, drizzled::internal::my_off_t filepos, unsigned char *buf)
379
 
{
380
 
  fast_mi_writeinfo(info);
381
 
  if (filepos != HA_OFFSET_ERROR)
382
 
  {
383
 
    if (info->lastinx >= 0)
384
 
    {                           /* Read only key */
385
 
      if (_mi_put_key_in_record(info,(uint) info->lastinx,buf))
386
 
      {
387
 
        mi_print_error(info->s, HA_ERR_CRASHED);
388
 
        errno=HA_ERR_CRASHED;
389
 
        return -1;
390
 
      }
391
 
      info->update|= HA_STATE_AKTIV; /* We should find a record */
392
 
      return 0;
393
 
    }
394
 
    errno=HA_ERR_WRONG_INDEX;
395
 
  }
396
 
  return(-1);                           /* Wrong data to read */
397
 
}
398
 
 
399
 
 
400
 
/*
401
 
  Save current key tuple to record and call index condition check function
402
 
 
403
 
  SYNOPSIS
404
 
    mi_check_index_cond()
405
 
      info    MyISAM handler
406
 
      keynr   Index we're running a scan on
407
 
      record  Record buffer to use (it is assumed that index check function
408
 
              will look for column values there)
409
 
 
410
 
  RETURN
411
 
    -1  Error
412
 
    0   Index condition is not satisfied, continue scanning
413
 
    1   Index condition is satisfied
414
 
    2   Index condition is not satisfied, end the scan.
415
 
*/
416
 
 
417
 
int mi_check_index_cond(register MI_INFO *info, uint32_t keynr, unsigned char *record)
418
 
{
419
 
  if (_mi_put_key_in_record(info, keynr, record))
420
 
  {
421
 
    mi_print_error(info->s, HA_ERR_CRASHED);
422
 
    errno=HA_ERR_CRASHED;
423
 
    return -1;
424
 
  }
425
 
  return info->index_cond_func(info->index_cond_func_arg);
426
 
}
427
 
 
428
 
 
429
 
/*
430
 
  Retrieve auto_increment info
431
 
 
432
 
  SYNOPSIS
433
 
    retrieve_auto_increment()
434
 
    info                        MyISAM handler
435
 
    record                      Row to update
436
 
 
437
 
  IMPLEMENTATION
438
 
    For signed columns we don't retrieve the auto increment value if it's
439
 
    less than zero.
440
 
*/
441
 
 
442
 
uint64_t retrieve_auto_increment(MI_INFO *info,const unsigned char *record)
443
 
{
444
 
  uint64_t value= 0;                    /* Store unsigned values here */
445
 
  int64_t s_value= 0;                   /* Store signed values here */
446
 
  HA_KEYSEG *keyseg= info->s->keyinfo[info->s->base.auto_key-1].seg;
447
 
  const unsigned char *key= (unsigned char*) record + keyseg->start;
448
 
 
449
 
  switch (keyseg->type) {
450
 
  case drizzled::HA_KEYTYPE_BINARY:
451
 
    value=(uint64_t)  *(unsigned char*) key;
452
 
    break;
453
 
  case drizzled::HA_KEYTYPE_LONG_INT:
454
 
    s_value= (int64_t) sint4korr(key);
455
 
    break;
456
 
  case drizzled::HA_KEYTYPE_ULONG_INT:
457
 
    value=(uint64_t) uint4korr(key);
458
 
    break;
459
 
  case drizzled::HA_KEYTYPE_DOUBLE:                       /* This shouldn't be used */
460
 
  {
461
 
    double f_1;
462
 
    float8get(f_1,key);
463
 
    /* Ignore negative values */
464
 
    value = (f_1 < 0.0) ? 0 : (uint64_t) f_1;
465
 
    break;
466
 
  }
467
 
  case drizzled::HA_KEYTYPE_LONGLONG:
468
 
    s_value= sint8korr(key);
469
 
    break;
470
 
  case drizzled::HA_KEYTYPE_ULONGLONG:
471
 
    value= uint8korr(key);
472
 
    break;
473
 
  default:
474
 
    assert(0);
475
 
    value=0;                                    /* Error */
476
 
    break;
477
 
  }
478
 
 
479
 
  /*
480
 
    The following code works becasue if s_value < 0 then value is 0
481
 
    and if s_value == 0 then value will contain either s_value or the
482
 
    correct value.
483
 
  */
484
 
  return (s_value > 0) ? (uint64_t) s_value : value;
485
 
}