~drizzle-trunk/drizzle/development

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