~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
17
/* Functions to handle keys and fields in forms */
18
934.2.21 by Jay Pipes
Move Key stuff into key.cc and out of session.cc
19
#include "drizzled/server_includes.h"
20
#include "drizzled/table.h"
21
#include "drizzled/key.h"
22
#include "drizzled/field/blob.h"
1 by brian
clean slate
23
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
24
#include <string>
25
26
using namespace std;
27
1 by brian
clean slate
28
/*
29
  Search after a key that starts with 'field'
30
31
  SYNOPSIS
32
    find_ref_key()
33
    key			First key to check
34
    key_count		How many keys to check
35
    record		Start of record
36
    field		Field to search after
37
    key_length		On partial match, contains length of fields before
38
			field
39
    keypart             key part # of a field
40
41
  NOTES
42
   Used when calculating key for NEXT_NUMBER
43
44
  IMPLEMENTATION
45
    If no key starts with field test if field is part of some key. If we find
46
    one, then return first key and set key_length to the number of bytes
47
    preceding 'field'.
48
49
  RETURN
50
   -1  field is not part of the key
51
   #   Key part for key matching key.
52
       key_length is set to length of key before (not including) field
53
*/
54
482 by Brian Aker
Remove uint.
55
int find_ref_key(KEY *key, uint32_t key_count, unsigned char *record, Field *field,
56
                 uint32_t *key_length, uint32_t *keypart)
1 by brian
clean slate
57
{
58
  register int i;
59
  register KEY *key_info;
482 by Brian Aker
Remove uint.
60
  uint32_t fieldpos;
1 by brian
clean slate
61
62
  fieldpos= field->offset(record);
63
64
  /* Test if some key starts as fieldpos */
65
  for (i= 0, key_info= key ;
66
       i < (int) key_count ;
67
       i++, key_info++)
68
  {
69
    if (key_info->key_part[0].offset == fieldpos)
70
    {                                  		/* Found key. Calc keylength */
71
      *key_length= *keypart= 0;
72
      return i;                                 /* Use this key */
73
    }
74
  }
75
76
  /* Test if some key contains fieldpos */
77
  for (i= 0, key_info= key;
78
       i < (int) key_count ;
79
       i++, key_info++)
80
  {
482 by Brian Aker
Remove uint.
81
    uint32_t j;
1 by brian
clean slate
82
    KEY_PART_INFO *key_part;
83
    *key_length=0;
84
    for (j=0, key_part=key_info->key_part ;
85
	 j < key_info->key_parts ;
86
	 j++, key_part++)
87
    {
88
      if (key_part->offset == fieldpos)
89
      {
90
        *keypart= j;
91
        return i;                               /* Use this key */
92
      }
93
      *key_length+= key_part->store_length;
94
    }
95
  }
96
  return(-1);					/* No key is ok */
97
}
98
99
481 by Brian Aker
Remove all of uchar.
100
void key_copy(unsigned char *to_key, unsigned char *from_record, KEY *key_info,
287.3.8 by Monty Taylor
Oy. Replaced max and min macros with std::max and std::min so that we get
101
              unsigned int key_length)
1 by brian
clean slate
102
{
482 by Brian Aker
Remove uint.
103
  uint32_t length;
1 by brian
clean slate
104
  KEY_PART_INFO *key_part;
105
106
  if (key_length == 0)
107
    key_length= key_info->key_length;
108
  for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
109
  {
110
    if (key_part->null_bit)
111
    {
112
      *to_key++= test(from_record[key_part->null_offset] &
113
		   key_part->null_bit);
114
      key_length--;
115
    }
116
    if (key_part->key_part_flag & HA_BLOB_PART ||
117
        key_part->key_part_flag & HA_VAR_LENGTH_PART)
118
    {
119
      key_length-= HA_KEY_BLOB_LENGTH;
398.1.4 by Monty Taylor
Renamed max/min.
120
      length= cmin((uint16_t)key_length, key_part->length);
1 by brian
clean slate
121
      key_part->field->get_key_image(to_key, length, Field::itRAW);
122
      to_key+= HA_KEY_BLOB_LENGTH;
123
    }
124
    else
125
    {
398.1.4 by Monty Taylor
Renamed max/min.
126
      length= cmin((uint16_t)key_length, key_part->length);
1 by brian
clean slate
127
      Field *field= key_part->field;
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
128
      const CHARSET_INFO * const cs= field->charset();
482 by Brian Aker
Remove uint.
129
      uint32_t bytes= field->get_key_image(to_key, length, Field::itRAW);
1 by brian
clean slate
130
      if (bytes < length)
131
        cs->cset->fill(cs, (char*) to_key + bytes, length - bytes, ' ');
132
    }
133
    to_key+= length;
134
    key_length-= length;
135
  }
136
}
137
138
139
/**
140
  Zero the null components of key tuple.
141
*/
142
481 by Brian Aker
Remove all of uchar.
143
void key_zero_nulls(unsigned char *tuple, KEY *key_info)
1 by brian
clean slate
144
{
145
  KEY_PART_INFO *key_part= key_info->key_part;
146
  KEY_PART_INFO *key_part_end= key_part + key_info->key_parts;
147
  for (; key_part != key_part_end; key_part++)
148
  {
149
    if (key_part->null_bit && *tuple)
212.6.1 by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file.
150
      memset(tuple+1, 0, key_part->store_length-1);
1 by brian
clean slate
151
    tuple+= key_part->store_length;
152
  }
153
}
154
155
156
/*
157
  Restore a key from some buffer to record.
158
159
    This function converts a key into record format. It can be used in cases
160
    when we want to return a key as a result row.
161
162
  @param to_record   record buffer where the key will be restored to
163
  @param from_key    buffer that contains a key
164
  @param key_info    descriptor of the index
165
  @param key_length  specifies length of all keyparts that will be restored
166
*/
167
481 by Brian Aker
Remove all of uchar.
168
void key_restore(unsigned char *to_record, unsigned char *from_key, KEY *key_info,
287.3.8 by Monty Taylor
Oy. Replaced max and min macros with std::max and std::min so that we get
169
                 uint16_t key_length)
1 by brian
clean slate
170
{
482 by Brian Aker
Remove uint.
171
  uint32_t length;
1 by brian
clean slate
172
  KEY_PART_INFO *key_part;
173
174
  if (key_length == 0)
175
  {
176
    key_length= key_info->key_length;
177
  }
178
  for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++)
179
  {
481 by Brian Aker
Remove all of uchar.
180
    unsigned char used_uneven_bits= 0;
1 by brian
clean slate
181
    if (key_part->null_bit)
182
    {
183
      if (*from_key++)
184
	to_record[key_part->null_offset]|= key_part->null_bit;
185
      else
186
	to_record[key_part->null_offset]&= ~key_part->null_bit;
187
      key_length--;
188
    }
189
    if (key_part->key_part_flag & HA_BLOB_PART)
190
    {
191
      /*
192
        This in fact never happens, as we have only partial BLOB
193
        keys yet anyway, so it's difficult to find any sence to
194
        restore the part of a record.
195
        Maybe this branch is to be removed, but now we
196
        have to ignore GCov compaining.
197
      */
482 by Brian Aker
Remove uint.
198
      uint32_t blob_length= uint2korr(from_key);
1 by brian
clean slate
199
      Field_blob *field= (Field_blob*) key_part->field;
200
      from_key+= HA_KEY_BLOB_LENGTH;
201
      key_length-= HA_KEY_BLOB_LENGTH;
202
      field->set_ptr_offset(to_record - field->table->record[0],
203
                            (ulong) blob_length, from_key);
204
      length= key_part->length;
205
    }
206
    else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
207
    {
208
      Field *field= key_part->field;
209
      my_ptrdiff_t ptrdiff= to_record - field->table->record[0];
210
      field->move_field_offset(ptrdiff);
211
      key_length-= HA_KEY_BLOB_LENGTH;
398.1.4 by Monty Taylor
Renamed max/min.
212
      length= cmin(key_length, key_part->length);
1 by brian
clean slate
213
      field->set_key_image(from_key, length);
214
      from_key+= HA_KEY_BLOB_LENGTH;
215
      field->move_field_offset(-ptrdiff);
216
    }
217
    else
218
    {
398.1.4 by Monty Taylor
Renamed max/min.
219
      length= cmin(key_length, key_part->length);
1 by brian
clean slate
220
      /* skip the byte with 'uneven' bits, if used */
221
      memcpy(to_record + key_part->offset, from_key + used_uneven_bits
222
             , (size_t) length - used_uneven_bits);
223
    }
224
    from_key+= length;
225
    key_length-= length;
226
  }
227
}
228
229
230
/**
231
  Compare if a key has changed.
232
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
233
  @param table		Table
1 by brian
clean slate
234
  @param key		key to compare to row
235
  @param idx		Index used
236
  @param key_length	Length of key
237
238
  @note
239
    In theory we could just call field->cmp() for all field types,
240
    but as we are only interested if a key has changed (not if the key is
241
    larger or smaller than the previous value) we can do things a bit
242
    faster by using memcmp() instead.
243
244
  @retval
245
    0	If key is equal
246
  @retval
247
    1	Key has changed
248
*/
249
482 by Brian Aker
Remove uint.
250
bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
1 by brian
clean slate
251
{
482 by Brian Aker
Remove uint.
252
  uint32_t store_length;
1 by brian
clean slate
253
  KEY_PART_INFO *key_part;
481 by Brian Aker
Remove all of uchar.
254
  const unsigned char *key_end= key + key_length;;
1 by brian
clean slate
255
256
  for (key_part=table->key_info[idx].key_part;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
257
       key < key_end ;
1 by brian
clean slate
258
       key_part++, key+= store_length)
259
  {
482 by Brian Aker
Remove uint.
260
    uint32_t length;
1 by brian
clean slate
261
    store_length= key_part->store_length;
262
263
    if (key_part->null_bit)
264
    {
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
265
      if (*key != test(table->record[0][key_part->null_offset] &
1 by brian
clean slate
266
		       key_part->null_bit))
267
	return 1;
268
      if (*key)
269
	continue;
270
      key++;
271
      store_length--;
272
    }
273
    if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART |
274
                                   HA_BIT_PART))
275
    {
276
      if (key_part->field->key_cmp(key, key_part->length))
277
	return 1;
278
      continue;
279
    }
895 by Brian Aker
Completion (?) of uint conversion.
280
    length= cmin((uint32_t) (key_end-key), store_length);
1 by brian
clean slate
281
    if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
282
                                FIELDFLAG_PACK)))
283
    {
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
284
      const CHARSET_INFO * const cs= key_part->field->charset();
482 by Brian Aker
Remove uint.
285
      uint32_t char_length= key_part->length / cs->mbmaxlen;
481 by Brian Aker
Remove all of uchar.
286
      const unsigned char *pos= table->record[0] + key_part->offset;
1 by brian
clean slate
287
      if (length > char_length)
288
      {
289
        char_length= my_charpos(cs, pos, pos + length, char_length);
290
        set_if_smaller(char_length, length);
291
      }
292
      if (cs->coll->strnncollsp(cs,
481 by Brian Aker
Remove all of uchar.
293
                                (const unsigned char*) key, length,
294
                                (const unsigned char*) pos, char_length, 0))
1 by brian
clean slate
295
        return 1;
296
      continue;
297
    }
298
    if (memcmp(key,table->record[0]+key_part->offset,length))
299
      return 1;
300
  }
301
  return 0;
302
}
303
304
/*
305
  unpack key-fields from record to some buffer.
306
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
307
  This is used mainly to get a good error message.  We temporary
1 by brian
clean slate
308
  change the column bitmap so that all columns are readable.
309
310
  @param
311
     to		Store value here in an easy to read form
312
  @param
313
     table	Table to use
314
  @param
315
     idx	Key number
316
*/
317
482 by Brian Aker
Remove uint.
318
void key_unpack(String *to,Table *table,uint32_t idx)
1 by brian
clean slate
319
{
320
  KEY_PART_INFO *key_part,*key_part_end;
321
  Field *field;
322
  String tmp;
323
324
  to->length(0);
325
  for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
326
	 table->key_info[idx].key_parts ;
327
       key_part < key_part_end;
328
       key_part++)
329
  {
330
    if (to->length())
331
      to->append('-');
332
    if (key_part->null_bit)
333
    {
334
      if (table->record[0][key_part->null_offset] & key_part->null_bit)
335
      {
336
	to->append(STRING_WITH_LEN("NULL"));
337
	continue;
338
      }
339
    }
340
    if ((field=key_part->field))
341
    {
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
342
      const CHARSET_INFO * const cs= field->charset();
1 by brian
clean slate
343
      field->val_str(&tmp);
344
      if (cs->mbmaxlen > 1 &&
345
          table->field[key_part->fieldnr - 1]->field_length !=
346
          key_part->length)
347
      {
348
        /*
349
          Prefix key, multi-byte charset.
350
          For the columns of type CHAR(N), the above val_str()
351
          call will return exactly "key_part->length" bytes,
352
          which can break a multi-byte characters in the middle.
353
          Align, returning not more than "char_length" characters.
354
        */
482 by Brian Aker
Remove uint.
355
        uint32_t charpos, char_length= key_part->length / cs->mbmaxlen;
813.1.3 by Jay Pipes
Incorrectly passing str.ptr() instead of str.c_ptr() to my_charpos() in key.cc:key_unpack(). This resulted in duplicate key error messages containing random characters due to a bad offset, and would show up as random failure in the myisam.test case when running make test but not ./dtr myisam.
356
        if ((charpos= my_charpos(cs, tmp.c_ptr(),
357
                                 tmp.c_ptr() + tmp.length(),
1 by brian
clean slate
358
                                 char_length)) < key_part->length)
359
          tmp.length(charpos);
360
      }
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
361
1 by brian
clean slate
362
      if (key_part->length < field->pack_length())
398.1.4 by Monty Taylor
Renamed max/min.
363
	tmp.length(cmin(tmp.length(),(uint32_t)key_part->length));
1 by brian
clean slate
364
      to->append(tmp);
365
    }
366
    else
367
      to->append(STRING_WITH_LEN("???"));
368
  }
327.2.3 by Brian Aker
Refactoring of class Table
369
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
370
  return;
1 by brian
clean slate
371
}
372
373
374
/*
375
  Check if key uses field that is marked in passed field bitmap.
376
377
  SYNOPSIS
378
    is_key_used()
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
379
      table   Table object with which keys and fields are associated.
1 by brian
clean slate
380
      idx     Key to be checked.
381
      fields  Bitmap of fields to be checked.
382
383
  NOTE
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
384
    This function uses Table::tmp_set bitmap so the caller should care
1 by brian
clean slate
385
    about saving/restoring its state if it also uses this bitmap.
386
387
  RETURN VALUE
388
    TRUE   Key uses field from bitmap
389
    FALSE  Otherwise
390
*/
391
1005.2.3 by Monty Taylor
Further reversion of P.
392
bool is_key_used(Table *table, uint32_t idx, const MY_BITMAP *fields)
1 by brian
clean slate
393
{
1005.2.3 by Monty Taylor
Further reversion of P.
394
  bitmap_clear_all(&table->tmp_set);
1 by brian
clean slate
395
  table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
1005.2.3 by Monty Taylor
Further reversion of P.
396
  if (bitmap_is_overlapping(&table->tmp_set, fields))
1 by brian
clean slate
397
    return 1;
398
399
  /*
400
    If table handler has primary key as part of the index, check that primary
401
    key is not updated
402
  */
403
  if (idx != table->s->primary_key && table->s->primary_key < MAX_KEY &&
404
      (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
405
    return is_key_used(table, table->s->primary_key, fields);
406
  return 0;
407
}
408
409
410
/**
411
  Compare key in row to a given key.
412
413
  @param key_part		Key part handler
414
  @param key			Key to compare to value in table->record[0]
415
  @param key_length		length of 'key'
416
417
  @return
418
    The return value is SIGN(key_in_row - range_key):
419
    -   0		Key is equal to range or 'range' == 0 (no range)
420
    -  -1		Key is less than range
421
    -   1		Key is larger than range
422
*/
423
482 by Brian Aker
Remove uint.
424
int key_cmp(KEY_PART_INFO *key_part, const unsigned char *key, uint32_t key_length)
1 by brian
clean slate
425
{
482 by Brian Aker
Remove uint.
426
  uint32_t store_length;
1 by brian
clean slate
427
481 by Brian Aker
Remove all of uchar.
428
  for (const unsigned char *end=key + key_length;
1 by brian
clean slate
429
       key < end;
430
       key+= store_length, key_part++)
431
  {
432
    int cmp;
433
    store_length= key_part->store_length;
434
    if (key_part->null_bit)
435
    {
436
      /* This key part allows null values; NULL is lower than everything */
437
      register bool field_is_null= key_part->field->is_null();
438
      if (*key)                                 // If range key is null
439
      {
440
	/* the range is expecting a null value */
441
	if (!field_is_null)
442
	  return 1;                             // Found key is > range
443
        /* null -- exact match, go to next key part */
444
	continue;
445
      }
446
      else if (field_is_null)
447
	return -1;                              // NULL is less than any value
448
      key++;					// Skip null byte
449
      store_length--;
450
    }
451
    if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0)
452
      return -1;
453
    if (cmp > 0)
454
      return 1;
455
  }
456
  return 0;                                     // Keys are equal
457
}
458
459
460
/*
461
  Compare two records in index order
462
  SYNOPSIS
463
    key_rec_cmp()
464
    key                         Index information
465
    rec0                        Pointer to table->record[0]
466
    first_rec                   Pointer to record compare with
467
    second_rec                  Pointer to record compare against first_rec
468
469
  DESCRIPTION
470
    This method is set-up such that it can be called directly from the
471
    priority queue and it is attempted to be optimised as much as possible
472
    since this will be called O(N * log N) times while performing a merge
473
    sort in various places in the code.
474
475
    We retrieve the pointer to table->record[0] using the fact that key_parts
476
    have an offset making it possible to calculate the start of the record.
477
    We need to get the diff to the compared record since none of the records
478
    being compared are stored in table->record[0].
479
480
    We first check for NULL values, if there are no NULL values we use
481
    a compare method that gets two field pointers and a max length
482
    and return the result of the comparison.
483
*/
484
481 by Brian Aker
Remove all of uchar.
485
int key_rec_cmp(void *key, unsigned char *first_rec, unsigned char *second_rec)
1 by brian
clean slate
486
{
487
  KEY *key_info= (KEY*)key;
482 by Brian Aker
Remove uint.
488
  uint32_t key_parts= key_info->key_parts, i= 0;
1 by brian
clean slate
489
  KEY_PART_INFO *key_part= key_info->key_part;
481 by Brian Aker
Remove all of uchar.
490
  unsigned char *rec0= key_part->field->ptr - key_part->offset;
1 by brian
clean slate
491
  my_ptrdiff_t first_diff= first_rec - rec0, sec_diff= second_rec - rec0;
492
  int result= 0;
493
494
  do
495
  {
496
    Field *field= key_part->field;
497
498
    if (key_part->null_bit)
499
    {
500
      /* The key_part can contain NULL values */
501
      bool first_is_null= field->is_null_in_record_with_offset(first_diff);
502
      bool sec_is_null= field->is_null_in_record_with_offset(sec_diff);
503
      /*
504
        NULL is smaller then everything so if first is NULL and the other
505
        not then we know that we should return -1 and for the opposite
506
        we should return +1. If both are NULL then we call it equality
507
        although it is a strange form of equality, we have equally little
508
        information of the real value.
509
      */
510
      if (!first_is_null)
511
      {
512
        if (!sec_is_null)
513
          ; /* Fall through, no NULL fields */
514
        else
515
        {
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
516
          return(1);
1 by brian
clean slate
517
        }
518
      }
519
      else if (!sec_is_null)
520
      {
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
521
        return(-1);
1 by brian
clean slate
522
      }
523
      else
524
        goto next_loop; /* Both were NULL */
525
    }
526
    /*
527
      No null values in the fields
528
      We use the virtual method cmp_max with a max length parameter.
529
      For most field types this translates into a cmp without
530
      max length. The exceptions are the BLOB and VARCHAR field types
531
      that take the max length into account.
532
    */
533
    result= field->cmp_max(field->ptr+first_diff, field->ptr+sec_diff,
534
                           key_part->length);
535
next_loop:
536
    key_part++;
537
  } while (!result && ++i < key_parts);
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
538
  return(result);
1 by brian
clean slate
539
}
934.2.21 by Jay Pipes
Move Key stuff into key.cc and out of session.cc
540
541
Key::Key(const Key &rhs, MEM_ROOT *mem_root)
542
  :type(rhs.type),
543
  key_create_info(rhs.key_create_info),
544
  columns(rhs.columns, mem_root),
545
  name(rhs.name),
546
  generated(rhs.generated)
547
{
548
  list_copy_and_replace_each_value(columns, mem_root);
549
}