~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/key.cc

  • Committer: devananda
  • Date: 2009-07-01 17:38:47 UTC
  • mto: (1093.1.7 captain)
  • mto: This revision was merged to the branch mainline in revision 1095.
  • Revision ID: devananda.vdv@gmail.com-20090701173847-3n3mbtessg5ff35e
refactored function/benchmark into plugin/benchmark

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"
 
19
#include "drizzled/server_includes.h"
20
20
#include "drizzled/table.h"
21
21
#include "drizzled/key.h"
22
22
#include "drizzled/field/blob.h"
23
 
#include "drizzled/util/test.h"
24
 
 
25
 
#include <boost/dynamic_bitset.hpp>
26
23
 
27
24
#include <string>
28
25
 
29
 
#include <algorithm>
30
 
 
31
26
using namespace std;
32
27
 
33
 
namespace drizzled
34
 
{
35
 
 
36
28
/*
37
29
  Search after a key that starts with 'field'
38
30
 
60
52
       key_length is set to length of key before (not including) field
61
53
*/
62
54
 
63
 
int find_ref_key(KeyInfo *key, uint32_t key_count, unsigned char *record, Field *field,
 
55
int find_ref_key(KEY *key, uint32_t key_count, unsigned char *record, Field *field,
64
56
                 uint32_t *key_length, uint32_t *keypart)
65
57
{
66
58
  register int i;
67
 
  register KeyInfo *key_info;
 
59
  register KEY *key_info;
68
60
  uint32_t fieldpos;
69
61
 
70
62
  fieldpos= field->offset(record);
87
79
       i++, key_info++)
88
80
  {
89
81
    uint32_t j;
90
 
    KeyPartInfo *key_part;
 
82
    KEY_PART_INFO *key_part;
91
83
    *key_length=0;
92
84
    for (j=0, key_part=key_info->key_part ;
93
85
         j < key_info->key_parts ;
105
97
}
106
98
 
107
99
 
108
 
void key_copy(unsigned char *to_key, unsigned char *from_record, KeyInfo *key_info,
 
100
void key_copy(unsigned char *to_key, unsigned char *from_record, KEY *key_info,
109
101
              unsigned int key_length)
110
102
{
111
103
  uint32_t length;
112
 
  KeyPartInfo *key_part;
 
104
  KEY_PART_INFO *key_part;
113
105
 
114
106
  if (key_length == 0)
115
107
    key_length= key_info->key_length;
125
117
        key_part->key_part_flag & HA_VAR_LENGTH_PART)
126
118
    {
127
119
      key_length-= HA_KEY_BLOB_LENGTH;
128
 
      length= min((uint16_t)key_length, key_part->length);
 
120
      length= cmin((uint16_t)key_length, key_part->length);
129
121
      key_part->field->get_key_image(to_key, length);
130
122
      to_key+= HA_KEY_BLOB_LENGTH;
131
123
    }
132
124
    else
133
125
    {
134
 
      length= min((uint16_t)key_length, key_part->length);
 
126
      length= cmin((uint16_t)key_length, key_part->length);
135
127
      Field *field= key_part->field;
136
128
      const CHARSET_INFO * const cs= field->charset();
137
129
      uint32_t bytes= field->get_key_image(to_key, length);
148
140
  Zero the null components of key tuple.
149
141
*/
150
142
 
151
 
void key_zero_nulls(unsigned char *tuple, KeyInfo *key_info)
 
143
void key_zero_nulls(unsigned char *tuple, KEY *key_info)
152
144
{
153
 
  KeyPartInfo *key_part= key_info->key_part;
154
 
  KeyPartInfo *key_part_end= key_part + key_info->key_parts;
 
145
  KEY_PART_INFO *key_part= key_info->key_part;
 
146
  KEY_PART_INFO *key_part_end= key_part + key_info->key_parts;
155
147
  for (; key_part != key_part_end; key_part++)
156
148
  {
157
149
    if (key_part->null_bit && *tuple)
173
165
  @param key_length  specifies length of all keyparts that will be restored
174
166
*/
175
167
 
176
 
void key_restore(unsigned char *to_record, unsigned char *from_key, KeyInfo *key_info,
 
168
void key_restore(unsigned char *to_record, unsigned char *from_key, KEY *key_info,
177
169
                 uint16_t key_length)
178
170
{
179
171
  uint32_t length;
180
 
  KeyPartInfo *key_part;
 
172
  KEY_PART_INFO *key_part;
181
173
 
182
174
  if (key_length == 0)
183
175
  {
202
194
        restore the part of a record.
203
195
        Maybe this branch is to be removed, but now we
204
196
        have to ignore GCov compaining.
205
 
 
206
 
        This may make more sense once we push down block lengths to the engine (aka partial retrieval).
207
197
      */
208
198
      uint32_t blob_length= uint2korr(from_key);
209
199
      Field_blob *field= (Field_blob*) key_part->field;
210
 
 
211
 
      field->setReadSet();
212
200
      from_key+= HA_KEY_BLOB_LENGTH;
213
201
      key_length-= HA_KEY_BLOB_LENGTH;
214
 
      field->set_ptr_offset(to_record - field->getTable()->getInsertRecord(),
 
202
      field->set_ptr_offset(to_record - field->table->record[0],
215
203
                            (ulong) blob_length, from_key);
216
204
      length= key_part->length;
217
205
    }
218
206
    else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
219
207
    {
220
208
      Field *field= key_part->field;
221
 
      ptrdiff_t ptrdiff= to_record - field->getTable()->getInsertRecord();
222
 
 
223
 
      field->setReadSet();
224
 
      field->setWriteSet();
 
209
      my_ptrdiff_t ptrdiff= to_record - field->table->record[0];
225
210
      field->move_field_offset(ptrdiff);
226
211
      key_length-= HA_KEY_BLOB_LENGTH;
227
 
      length= min(key_length, key_part->length);
 
212
      length= cmin(key_length, key_part->length);
228
213
      field->set_key_image(from_key, length);
229
214
      from_key+= HA_KEY_BLOB_LENGTH;
230
215
      field->move_field_offset(-ptrdiff);
231
216
    }
232
217
    else
233
218
    {
234
 
      length= min(key_length, key_part->length);
 
219
      length= cmin(key_length, key_part->length);
235
220
      /* skip the byte with 'uneven' bits, if used */
236
221
      memcpy(to_record + key_part->offset, from_key + used_uneven_bits
237
222
             , (size_t) length - used_uneven_bits);
265
250
bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
266
251
{
267
252
  uint32_t store_length;
268
 
  KeyPartInfo *key_part;
 
253
  KEY_PART_INFO *key_part;
269
254
  const unsigned char *key_end= key + key_length;;
270
255
 
271
256
  for (key_part=table->key_info[idx].key_part;
277
262
 
278
263
    if (key_part->null_bit)
279
264
    {
280
 
      if (*key != test(table->getInsertRecord()[key_part->null_offset] &
 
265
      if (*key != test(table->record[0][key_part->null_offset] &
281
266
                       key_part->null_bit))
282
267
        return 1;
283
268
      if (*key)
292
277
        return 1;
293
278
      continue;
294
279
    }
295
 
    length= min((uint32_t) (key_end-key), store_length);
296
 
    if (key_part->field->type() == DRIZZLE_TYPE_VARCHAR)
 
280
    length= cmin((uint32_t) (key_end-key), store_length);
 
281
    if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
 
282
                                FIELDFLAG_PACK)))
297
283
    {
298
284
      const CHARSET_INFO * const cs= key_part->field->charset();
299
285
      uint32_t char_length= key_part->length / cs->mbmaxlen;
300
 
      const unsigned char *pos= table->getInsertRecord() + key_part->offset;
 
286
      const unsigned char *pos= table->record[0] + key_part->offset;
301
287
      if (length > char_length)
302
288
      {
303
289
        char_length= my_charpos(cs, pos, pos + length, char_length);
309
295
        return 1;
310
296
      continue;
311
297
    }
312
 
    if (memcmp(key,table->getInsertRecord()+key_part->offset,length))
 
298
    if (memcmp(key,table->record[0]+key_part->offset,length))
313
299
      return 1;
314
300
  }
315
301
  return 0;
329
315
     idx        Key number
330
316
*/
331
317
 
332
 
void key_unpack(String *to, Table *table, uint32_t idx)
 
318
void key_unpack(String *to,Table *table,uint32_t idx)
333
319
{
334
 
  KeyPartInfo *key_part,*key_part_end;
 
320
  KEY_PART_INFO *key_part,*key_part_end;
335
321
  Field *field;
336
322
  String tmp;
337
323
 
345
331
      to->append('-');
346
332
    if (key_part->null_bit)
347
333
    {
348
 
      if (table->getInsertRecord()[key_part->null_offset] & key_part->null_bit)
 
334
      if (table->record[0][key_part->null_offset] & key_part->null_bit)
349
335
      {
350
336
        to->append(STRING_WITH_LEN("NULL"));
351
337
        continue;
352
338
      }
353
339
    }
354
 
    if ((field= key_part->field))
 
340
    if ((field=key_part->field))
355
341
    {
356
342
      const CHARSET_INFO * const cs= field->charset();
357
 
      field->setReadSet();
358
 
      field->val_str_internal(&tmp);
 
343
      field->val_str(&tmp);
359
344
      if (cs->mbmaxlen > 1 &&
360
 
          table->getField(key_part->fieldnr - 1)->field_length !=
 
345
          table->field[key_part->fieldnr - 1]->field_length !=
361
346
          key_part->length)
362
347
      {
363
348
        /*
375
360
      }
376
361
 
377
362
      if (key_part->length < field->pack_length())
378
 
        tmp.length(min(tmp.length(), static_cast<size_t>(key_part->length)));
 
363
        tmp.length(cmin(tmp.length(),(uint32_t)key_part->length));
379
364
      to->append(tmp);
380
365
    }
381
366
    else
382
367
      to->append(STRING_WITH_LEN("???"));
383
368
  }
 
369
 
 
370
  return;
384
371
}
385
372
 
386
373
 
402
389
    FALSE  Otherwise
403
390
*/
404
391
 
405
 
bool is_key_used(Table *table, uint32_t idx, const boost::dynamic_bitset<>& fields)
 
392
bool is_key_used(Table *table, uint32_t idx, const MY_BITMAP *fields)
406
393
{
407
 
  table->tmp_set.reset();
408
 
  table->mark_columns_used_by_index_no_reset(idx, table->tmp_set);
409
 
  if (table->tmp_set.is_subset_of(fields))
 
394
  bitmap_clear_all(&table->tmp_set);
 
395
  table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
 
396
  if (bitmap_is_overlapping(&table->tmp_set, fields))
410
397
    return 1;
411
398
 
412
399
  /*
413
400
    If table handler has primary key as part of the index, check that primary
414
401
    key is not updated
415
402
  */
416
 
  if (idx != table->getShare()->getPrimaryKey() && table->getShare()->hasPrimaryKey() &&
417
 
      (table->cursor->getEngine()->check_flag(HTON_BIT_PRIMARY_KEY_IN_READ_INDEX)))
418
 
  {
419
 
    return is_key_used(table, table->getShare()->getPrimaryKey(), fields);
420
 
  }
 
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);
421
406
  return 0;
422
407
}
423
408
 
426
411
  Compare key in row to a given key.
427
412
 
428
413
  @param key_part               Key part handler
429
 
  @param key                    Key to compare to value in table->getInsertRecord()
 
414
  @param key                    Key to compare to value in table->record[0]
430
415
  @param key_length             length of 'key'
431
416
 
432
417
  @return
436
421
    -   1               Key is larger than range
437
422
*/
438
423
 
439
 
int key_cmp(KeyPartInfo *key_part, const unsigned char *key, uint32_t key_length)
 
424
int key_cmp(KEY_PART_INFO *key_part, const unsigned char *key, uint32_t key_length)
440
425
{
441
426
  uint32_t store_length;
442
427
 
472
457
}
473
458
 
474
459
 
475
 
} /* namespace drizzled */
 
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
 
 
485
int key_rec_cmp(void *key, unsigned char *first_rec, unsigned char *second_rec)
 
486
{
 
487
  KEY *key_info= (KEY*)key;
 
488
  uint32_t key_parts= key_info->key_parts, i= 0;
 
489
  KEY_PART_INFO *key_part= key_info->key_part;
 
490
  unsigned char *rec0= key_part->field->ptr - key_part->offset;
 
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
        {
 
516
          return(1);
 
517
        }
 
518
      }
 
519
      else if (!sec_is_null)
 
520
      {
 
521
        return(-1);
 
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);
 
538
  return(result);
 
539
}
 
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
}