~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/key.cc

  • Committer: Brian Aker
  • Date: 2008-10-29 13:46:43 UTC
  • Revision ID: brian@tangent.org-20081029134643-z6jcwjvyruhk2vlu
Updates for ignore file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
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 */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
 
17
17
/* Functions to handle keys and fields in forms */
18
18
 
19
 
#include <config.h>
20
 
#include <drizzled/table.h>
21
 
#include <drizzled/key.h>
22
 
#include <drizzled/field/blob.h>
23
 
#include <drizzled/util/test.h>
24
 
#include <drizzled/plugin/storage_engine.h>
25
 
 
26
 
#include <boost/dynamic_bitset.hpp>
27
 
 
28
 
#include <string>
29
 
 
30
 
#include <algorithm>
31
 
 
32
 
using namespace std;
33
 
 
34
 
namespace drizzled
35
 
{
 
19
#include <drizzled/server_includes.h>
36
20
 
37
21
/*
38
22
  Search after a key that starts with 'field'
61
45
       key_length is set to length of key before (not including) field
62
46
*/
63
47
 
64
 
int find_ref_key(KeyInfo *key, uint32_t key_count, unsigned char *record, Field *field,
 
48
int find_ref_key(KEY *key, uint32_t key_count, unsigned char *record, Field *field,
65
49
                 uint32_t *key_length, uint32_t *keypart)
66
50
{
67
 
  int i;
68
 
  KeyInfo *key_info;
 
51
  register int i;
 
52
  register KEY *key_info;
69
53
  uint32_t fieldpos;
70
54
 
71
55
  fieldpos= field->offset(record);
88
72
       i++, key_info++)
89
73
  {
90
74
    uint32_t j;
91
 
    KeyPartInfo *key_part;
 
75
    KEY_PART_INFO *key_part;
92
76
    *key_length=0;
93
77
    for (j=0, key_part=key_info->key_part ;
94
78
         j < key_info->key_parts ;
106
90
}
107
91
 
108
92
 
109
 
void key_copy(unsigned char *to_key, unsigned char *from_record, KeyInfo *key_info,
 
93
/**
 
94
  Copy part of a record that forms a key or key prefix to a buffer.
 
95
 
 
96
    The function takes a complete table record (as e.g. retrieved by
 
97
    handler::index_read()), and a description of an index on the same table,
 
98
    and extracts the first key_length bytes of the record which are part of a
 
99
    key into to_key. If length == 0 then copy all bytes from the record that
 
100
    form a key.
 
101
 
 
102
  @param to_key      buffer that will be used as a key
 
103
  @param from_record full record to be copied from
 
104
  @param key_info    descriptor of the index
 
105
  @param key_length  specifies length of all keyparts that will be copied
 
106
*/
 
107
 
 
108
void key_copy(unsigned char *to_key, unsigned char *from_record, KEY *key_info,
110
109
              unsigned int key_length)
111
110
{
112
111
  uint32_t length;
113
 
  KeyPartInfo *key_part;
 
112
  KEY_PART_INFO *key_part;
114
113
 
115
114
  if (key_length == 0)
116
115
    key_length= key_info->key_length;
126
125
        key_part->key_part_flag & HA_VAR_LENGTH_PART)
127
126
    {
128
127
      key_length-= HA_KEY_BLOB_LENGTH;
129
 
      length= min((uint16_t)key_length, key_part->length);
130
 
      key_part->field->get_key_image(to_key, length);
 
128
      length= cmin((uint16_t)key_length, key_part->length);
 
129
      key_part->field->get_key_image(to_key, length, Field::itRAW);
131
130
      to_key+= HA_KEY_BLOB_LENGTH;
132
131
    }
133
132
    else
134
133
    {
135
 
      length= min((uint16_t)key_length, key_part->length);
 
134
      length= cmin((uint16_t)key_length, key_part->length);
136
135
      Field *field= key_part->field;
137
136
      const CHARSET_INFO * const cs= field->charset();
138
 
      uint32_t bytes= field->get_key_image(to_key, length);
 
137
      uint32_t bytes= field->get_key_image(to_key, length, Field::itRAW);
139
138
      if (bytes < length)
140
139
        cs->cset->fill(cs, (char*) to_key + bytes, length - bytes, ' ');
141
140
    }
149
148
  Zero the null components of key tuple.
150
149
*/
151
150
 
152
 
void key_zero_nulls(unsigned char *tuple, KeyInfo *key_info)
 
151
void key_zero_nulls(unsigned char *tuple, KEY *key_info)
153
152
{
154
 
  KeyPartInfo *key_part= key_info->key_part;
155
 
  KeyPartInfo *key_part_end= key_part + key_info->key_parts;
 
153
  KEY_PART_INFO *key_part= key_info->key_part;
 
154
  KEY_PART_INFO *key_part_end= key_part + key_info->key_parts;
156
155
  for (; key_part != key_part_end; key_part++)
157
156
  {
158
157
    if (key_part->null_bit && *tuple)
174
173
  @param key_length  specifies length of all keyparts that will be restored
175
174
*/
176
175
 
177
 
void key_restore(unsigned char *to_record, unsigned char *from_key, KeyInfo *key_info,
 
176
void key_restore(unsigned char *to_record, unsigned char *from_key, KEY *key_info,
178
177
                 uint16_t key_length)
179
178
{
180
179
  uint32_t length;
181
 
  KeyPartInfo *key_part;
 
180
  KEY_PART_INFO *key_part;
182
181
 
183
182
  if (key_length == 0)
184
183
  {
203
202
        restore the part of a record.
204
203
        Maybe this branch is to be removed, but now we
205
204
        have to ignore GCov compaining.
206
 
 
207
 
        This may make more sense once we push down block lengths to the engine (aka partial retrieval).
208
205
      */
209
206
      uint32_t blob_length= uint2korr(from_key);
210
207
      Field_blob *field= (Field_blob*) key_part->field;
211
 
 
212
 
      field->setReadSet();
213
208
      from_key+= HA_KEY_BLOB_LENGTH;
214
209
      key_length-= HA_KEY_BLOB_LENGTH;
215
 
      field->set_ptr_offset(to_record - field->getTable()->getInsertRecord(),
 
210
      field->set_ptr_offset(to_record - field->table->record[0],
216
211
                            (ulong) blob_length, from_key);
217
212
      length= key_part->length;
218
213
    }
219
214
    else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
220
215
    {
221
216
      Field *field= key_part->field;
222
 
      ptrdiff_t ptrdiff= to_record - field->getTable()->getInsertRecord();
223
 
 
224
 
      field->setReadSet();
225
 
      field->setWriteSet();
 
217
      my_ptrdiff_t ptrdiff= to_record - field->table->record[0];
226
218
      field->move_field_offset(ptrdiff);
227
219
      key_length-= HA_KEY_BLOB_LENGTH;
228
 
      length= min(key_length, key_part->length);
 
220
      length= cmin(key_length, key_part->length);
229
221
      field->set_key_image(from_key, length);
230
222
      from_key+= HA_KEY_BLOB_LENGTH;
231
223
      field->move_field_offset(-ptrdiff);
232
224
    }
233
225
    else
234
226
    {
235
 
      length= min(key_length, key_part->length);
 
227
      length= cmin(key_length, key_part->length);
236
228
      /* skip the byte with 'uneven' bits, if used */
237
229
      memcpy(to_record + key_part->offset, from_key + used_uneven_bits
238
230
             , (size_t) length - used_uneven_bits);
266
258
bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
267
259
{
268
260
  uint32_t store_length;
269
 
  KeyPartInfo *key_part;
 
261
  KEY_PART_INFO *key_part;
270
262
  const unsigned char *key_end= key + key_length;;
271
263
 
272
264
  for (key_part=table->key_info[idx].key_part;
273
 
       key < key_end ;
 
265
       key < key_end ; 
274
266
       key_part++, key+= store_length)
275
267
  {
276
268
    uint32_t length;
278
270
 
279
271
    if (key_part->null_bit)
280
272
    {
281
 
      if (*key != test(table->getInsertRecord()[key_part->null_offset] &
 
273
      if (*key != test(table->record[0][key_part->null_offset] & 
282
274
                       key_part->null_bit))
283
275
        return 1;
284
276
      if (*key)
293
285
        return 1;
294
286
      continue;
295
287
    }
296
 
    length= min((uint32_t) (key_end-key), store_length);
297
 
    if (key_part->field->type() == DRIZZLE_TYPE_VARCHAR)
 
288
    length= cmin((uint) (key_end-key), store_length);
 
289
    if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
 
290
                                FIELDFLAG_PACK)))
298
291
    {
299
292
      const CHARSET_INFO * const cs= key_part->field->charset();
300
293
      uint32_t char_length= key_part->length / cs->mbmaxlen;
301
 
      const unsigned char *pos= table->getInsertRecord() + key_part->offset;
 
294
      const unsigned char *pos= table->record[0] + key_part->offset;
302
295
      if (length > char_length)
303
296
      {
304
297
        char_length= my_charpos(cs, pos, pos + length, char_length);
310
303
        return 1;
311
304
      continue;
312
305
    }
313
 
    if (memcmp(key,table->getInsertRecord()+key_part->offset,length))
 
306
    if (memcmp(key,table->record[0]+key_part->offset,length))
314
307
      return 1;
315
308
  }
316
309
  return 0;
319
312
/*
320
313
  unpack key-fields from record to some buffer.
321
314
 
322
 
  This is used mainly to get a good error message.  We temporary
 
315
  This is used mainly to get a good error message.  We temporary 
323
316
  change the column bitmap so that all columns are readable.
324
317
 
325
318
  @param
330
323
     idx        Key number
331
324
*/
332
325
 
333
 
void key_unpack(String *to, const Table *table, uint32_t idx)
 
326
void key_unpack(String *to,Table *table,uint32_t idx)
334
327
{
335
 
  KeyPartInfo *key_part,*key_part_end;
 
328
  KEY_PART_INFO *key_part,*key_part_end;
336
329
  Field *field;
337
330
  String tmp;
338
331
 
346
339
      to->append('-');
347
340
    if (key_part->null_bit)
348
341
    {
349
 
      if (table->getInsertRecord()[key_part->null_offset] & key_part->null_bit)
 
342
      if (table->record[0][key_part->null_offset] & key_part->null_bit)
350
343
      {
351
344
        to->append(STRING_WITH_LEN("NULL"));
352
345
        continue;
353
346
      }
354
347
    }
355
 
    if ((field= key_part->field))
 
348
    if ((field=key_part->field))
356
349
    {
357
350
      const CHARSET_INFO * const cs= field->charset();
358
 
      field->setReadSet();
359
 
      field->val_str_internal(&tmp);
 
351
      field->val_str(&tmp);
360
352
      if (cs->mbmaxlen > 1 &&
361
 
          table->getField(key_part->fieldnr - 1)->field_length !=
 
353
          table->field[key_part->fieldnr - 1]->field_length !=
362
354
          key_part->length)
363
355
      {
364
356
        /*
369
361
          Align, returning not more than "char_length" characters.
370
362
        */
371
363
        uint32_t charpos, char_length= key_part->length / cs->mbmaxlen;
372
 
        if ((charpos= my_charpos(cs, tmp.c_ptr(),
373
 
                                 tmp.c_ptr() + tmp.length(),
 
364
        if ((charpos= my_charpos(cs, tmp.ptr(),
 
365
                                 tmp.ptr() + tmp.length(),
374
366
                                 char_length)) < key_part->length)
375
367
          tmp.length(charpos);
376
368
      }
377
 
 
 
369
      
378
370
      if (key_part->length < field->pack_length())
379
 
        tmp.length(min(tmp.length(), static_cast<size_t>(key_part->length)));
 
371
        tmp.length(cmin(tmp.length(),(uint32_t)key_part->length));
380
372
      to->append(tmp);
381
373
    }
382
374
    else
383
375
      to->append(STRING_WITH_LEN("???"));
384
376
  }
 
377
 
 
378
  return;
385
379
}
386
380
 
387
381
 
403
397
    FALSE  Otherwise
404
398
*/
405
399
 
406
 
bool is_key_used(Table *table, uint32_t idx, const boost::dynamic_bitset<>& fields)
 
400
bool is_key_used(Table *table, uint32_t idx, const MY_BITMAP *fields)
407
401
{
408
 
  table->tmp_set.reset();
409
 
  table->mark_columns_used_by_index_no_reset(idx, table->tmp_set);
410
 
  if (table->tmp_set.is_subset_of(fields))
 
402
  bitmap_clear_all(&table->tmp_set);
 
403
  table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
 
404
  if (bitmap_is_overlapping(&table->tmp_set, fields))
411
405
    return 1;
412
406
 
413
407
  /*
414
408
    If table handler has primary key as part of the index, check that primary
415
409
    key is not updated
416
410
  */
417
 
  if (idx != table->getShare()->getPrimaryKey() && table->getShare()->hasPrimaryKey() &&
418
 
      (table->cursor->getEngine()->check_flag(HTON_BIT_PRIMARY_KEY_IN_READ_INDEX)))
419
 
  {
420
 
    return is_key_used(table, table->getShare()->getPrimaryKey(), fields);
421
 
  }
 
411
  if (idx != table->s->primary_key && table->s->primary_key < MAX_KEY &&
 
412
      (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
 
413
    return is_key_used(table, table->s->primary_key, fields);
422
414
  return 0;
423
415
}
424
416
 
427
419
  Compare key in row to a given key.
428
420
 
429
421
  @param key_part               Key part handler
430
 
  @param key                    Key to compare to value in table->getInsertRecord()
 
422
  @param key                    Key to compare to value in table->record[0]
431
423
  @param key_length             length of 'key'
432
424
 
433
425
  @return
437
429
    -   1               Key is larger than range
438
430
*/
439
431
 
440
 
int key_cmp(KeyPartInfo *key_part, const unsigned char *key, uint32_t key_length)
 
432
int key_cmp(KEY_PART_INFO *key_part, const unsigned char *key, uint32_t key_length)
441
433
{
442
434
  uint32_t store_length;
443
435
 
450
442
    if (key_part->null_bit)
451
443
    {
452
444
      /* This key part allows null values; NULL is lower than everything */
453
 
      bool field_is_null= key_part->field->is_null();
 
445
      register bool field_is_null= key_part->field->is_null();
454
446
      if (*key)                                 // If range key is null
455
447
      {
456
448
        /* the range is expecting a null value */
473
465
}
474
466
 
475
467
 
476
 
} /* namespace drizzled */
 
468
/*
 
469
  Compare two records in index order
 
470
  SYNOPSIS
 
471
    key_rec_cmp()
 
472
    key                         Index information
 
473
    rec0                        Pointer to table->record[0]
 
474
    first_rec                   Pointer to record compare with
 
475
    second_rec                  Pointer to record compare against first_rec
 
476
 
 
477
  DESCRIPTION
 
478
    This method is set-up such that it can be called directly from the
 
479
    priority queue and it is attempted to be optimised as much as possible
 
480
    since this will be called O(N * log N) times while performing a merge
 
481
    sort in various places in the code.
 
482
 
 
483
    We retrieve the pointer to table->record[0] using the fact that key_parts
 
484
    have an offset making it possible to calculate the start of the record.
 
485
    We need to get the diff to the compared record since none of the records
 
486
    being compared are stored in table->record[0].
 
487
 
 
488
    We first check for NULL values, if there are no NULL values we use
 
489
    a compare method that gets two field pointers and a max length
 
490
    and return the result of the comparison.
 
491
*/
 
492
 
 
493
int key_rec_cmp(void *key, unsigned char *first_rec, unsigned char *second_rec)
 
494
{
 
495
  KEY *key_info= (KEY*)key;
 
496
  uint32_t key_parts= key_info->key_parts, i= 0;
 
497
  KEY_PART_INFO *key_part= key_info->key_part;
 
498
  unsigned char *rec0= key_part->field->ptr - key_part->offset;
 
499
  my_ptrdiff_t first_diff= first_rec - rec0, sec_diff= second_rec - rec0;
 
500
  int result= 0;
 
501
 
 
502
  do
 
503
  {
 
504
    Field *field= key_part->field;
 
505
 
 
506
    if (key_part->null_bit)
 
507
    {
 
508
      /* The key_part can contain NULL values */
 
509
      bool first_is_null= field->is_null_in_record_with_offset(first_diff);
 
510
      bool sec_is_null= field->is_null_in_record_with_offset(sec_diff);
 
511
      /*
 
512
        NULL is smaller then everything so if first is NULL and the other
 
513
        not then we know that we should return -1 and for the opposite
 
514
        we should return +1. If both are NULL then we call it equality
 
515
        although it is a strange form of equality, we have equally little
 
516
        information of the real value.
 
517
      */
 
518
      if (!first_is_null)
 
519
      {
 
520
        if (!sec_is_null)
 
521
          ; /* Fall through, no NULL fields */
 
522
        else
 
523
        {
 
524
          return(1);
 
525
        }
 
526
      }
 
527
      else if (!sec_is_null)
 
528
      {
 
529
        return(-1);
 
530
      }
 
531
      else
 
532
        goto next_loop; /* Both were NULL */
 
533
    }
 
534
    /*
 
535
      No null values in the fields
 
536
      We use the virtual method cmp_max with a max length parameter.
 
537
      For most field types this translates into a cmp without
 
538
      max length. The exceptions are the BLOB and VARCHAR field types
 
539
      that take the max length into account.
 
540
    */
 
541
    result= field->cmp_max(field->ptr+first_diff, field->ptr+sec_diff,
 
542
                           key_part->length);
 
543
next_loop:
 
544
    key_part++;
 
545
  } while (!result && ++i < key_parts);
 
546
  return(result);
 
547
}