~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/key.cc

  • Committer: Monty Taylor
  • Date: 2009-03-02 23:14:32 UTC
  • mto: This revision was merged to the branch mainline in revision 910.
  • Revision ID: mordred@inaugust.com-20090302231432-i35xehp7uzo6hjjw
Updated build system to use new version numbering. Just remember to run ./config/autorun.sh before running make distcheck for release and all should be peachy.

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
 
#include <drizzled/key.h>
22
21
#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
22
 
28
23
#include <string>
29
24
 
30
 
#include <algorithm>
31
 
 
32
25
using namespace std;
33
26
 
34
 
namespace drizzled
35
 
{
36
 
 
37
27
/*
38
28
  Search after a key that starts with 'field'
39
29
 
61
51
       key_length is set to length of key before (not including) field
62
52
*/
63
53
 
64
 
int find_ref_key(KeyInfo *key, uint32_t key_count, unsigned char *record, Field *field,
 
54
int find_ref_key(KEY *key, uint32_t key_count, unsigned char *record, Field *field,
65
55
                 uint32_t *key_length, uint32_t *keypart)
66
56
{
67
 
  int i;
68
 
  KeyInfo *key_info;
 
57
  register int i;
 
58
  register KEY *key_info;
69
59
  uint32_t fieldpos;
70
60
 
71
61
  fieldpos= field->offset(record);
88
78
       i++, key_info++)
89
79
  {
90
80
    uint32_t j;
91
 
    KeyPartInfo *key_part;
 
81
    KEY_PART_INFO *key_part;
92
82
    *key_length=0;
93
83
    for (j=0, key_part=key_info->key_part ;
94
84
         j < key_info->key_parts ;
106
96
}
107
97
 
108
98
 
109
 
void key_copy(unsigned char *to_key, unsigned char *from_record, KeyInfo *key_info,
 
99
void key_copy(unsigned char *to_key, unsigned char *from_record, KEY *key_info,
110
100
              unsigned int key_length)
111
101
{
112
102
  uint32_t length;
113
 
  KeyPartInfo *key_part;
 
103
  KEY_PART_INFO *key_part;
114
104
 
115
105
  if (key_length == 0)
116
106
    key_length= key_info->key_length;
126
116
        key_part->key_part_flag & HA_VAR_LENGTH_PART)
127
117
    {
128
118
      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);
 
119
      length= cmin((uint16_t)key_length, key_part->length);
 
120
      key_part->field->get_key_image(to_key, length, Field::itRAW);
131
121
      to_key+= HA_KEY_BLOB_LENGTH;
132
122
    }
133
123
    else
134
124
    {
135
 
      length= min((uint16_t)key_length, key_part->length);
 
125
      length= cmin((uint16_t)key_length, key_part->length);
136
126
      Field *field= key_part->field;
137
127
      const CHARSET_INFO * const cs= field->charset();
138
 
      uint32_t bytes= field->get_key_image(to_key, length);
 
128
      uint32_t bytes= field->get_key_image(to_key, length, Field::itRAW);
139
129
      if (bytes < length)
140
130
        cs->cset->fill(cs, (char*) to_key + bytes, length - bytes, ' ');
141
131
    }
145
135
}
146
136
 
147
137
 
 
138
void key_copy(basic_string<unsigned char> &to_key,
 
139
              unsigned char *from_record, KEY *key_info,
 
140
              unsigned int key_length)
 
141
{
 
142
  uint32_t length;
 
143
  KEY_PART_INFO *key_part;
 
144
 
 
145
  if (key_length == 0)
 
146
    key_length= key_info->key_length;
 
147
  for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
 
148
  {
 
149
    if (key_part->null_bit)
 
150
    {
 
151
      to_key.push_back(test(from_record[key_part->null_offset] &
 
152
                       key_part->null_bit) ? '1' : '0');
 
153
      key_length--;
 
154
    }
 
155
    if (key_part->key_part_flag & HA_BLOB_PART ||
 
156
        key_part->key_part_flag & HA_VAR_LENGTH_PART)
 
157
    {
 
158
      key_length-= HA_KEY_BLOB_LENGTH;
 
159
      length= cmin((uint16_t)key_length, key_part->length);
 
160
      key_part->field->get_key_image(to_key, length, Field::itRAW);
 
161
      to_key.append(HA_KEY_BLOB_LENGTH, '0');
 
162
    }
 
163
    else
 
164
    {
 
165
      length= cmin((uint16_t)key_length, key_part->length);
 
166
      Field *field= key_part->field;
 
167
      uint32_t bytes= field->get_key_image(to_key, length, Field::itRAW);
 
168
      if (bytes < length)
 
169
        to_key.append(length-bytes, ' ');
 
170
    }
 
171
    key_length-= length;
 
172
  }
 
173
}
 
174
 
 
175
 
148
176
/**
149
177
  Zero the null components of key tuple.
150
178
*/
151
179
 
152
 
void key_zero_nulls(unsigned char *tuple, KeyInfo *key_info)
 
180
void key_zero_nulls(unsigned char *tuple, KEY *key_info)
153
181
{
154
 
  KeyPartInfo *key_part= key_info->key_part;
155
 
  KeyPartInfo *key_part_end= key_part + key_info->key_parts;
 
182
  KEY_PART_INFO *key_part= key_info->key_part;
 
183
  KEY_PART_INFO *key_part_end= key_part + key_info->key_parts;
156
184
  for (; key_part != key_part_end; key_part++)
157
185
  {
158
186
    if (key_part->null_bit && *tuple)
174
202
  @param key_length  specifies length of all keyparts that will be restored
175
203
*/
176
204
 
177
 
void key_restore(unsigned char *to_record, unsigned char *from_key, KeyInfo *key_info,
 
205
void key_restore(unsigned char *to_record, unsigned char *from_key, KEY *key_info,
178
206
                 uint16_t key_length)
179
207
{
180
208
  uint32_t length;
181
 
  KeyPartInfo *key_part;
 
209
  KEY_PART_INFO *key_part;
182
210
 
183
211
  if (key_length == 0)
184
212
  {
203
231
        restore the part of a record.
204
232
        Maybe this branch is to be removed, but now we
205
233
        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
234
      */
209
235
      uint32_t blob_length= uint2korr(from_key);
210
236
      Field_blob *field= (Field_blob*) key_part->field;
211
 
 
212
 
      field->setReadSet();
213
237
      from_key+= HA_KEY_BLOB_LENGTH;
214
238
      key_length-= HA_KEY_BLOB_LENGTH;
215
 
      field->set_ptr_offset(to_record - field->getTable()->getInsertRecord(),
 
239
      field->set_ptr_offset(to_record - field->table->record[0],
216
240
                            (ulong) blob_length, from_key);
217
241
      length= key_part->length;
218
242
    }
219
243
    else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
220
244
    {
221
245
      Field *field= key_part->field;
222
 
      ptrdiff_t ptrdiff= to_record - field->getTable()->getInsertRecord();
223
 
 
224
 
      field->setReadSet();
225
 
      field->setWriteSet();
 
246
      my_ptrdiff_t ptrdiff= to_record - field->table->record[0];
226
247
      field->move_field_offset(ptrdiff);
227
248
      key_length-= HA_KEY_BLOB_LENGTH;
228
 
      length= min(key_length, key_part->length);
 
249
      length= cmin(key_length, key_part->length);
229
250
      field->set_key_image(from_key, length);
230
251
      from_key+= HA_KEY_BLOB_LENGTH;
231
252
      field->move_field_offset(-ptrdiff);
232
253
    }
233
254
    else
234
255
    {
235
 
      length= min(key_length, key_part->length);
 
256
      length= cmin(key_length, key_part->length);
236
257
      /* skip the byte with 'uneven' bits, if used */
237
258
      memcpy(to_record + key_part->offset, from_key + used_uneven_bits
238
259
             , (size_t) length - used_uneven_bits);
266
287
bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
267
288
{
268
289
  uint32_t store_length;
269
 
  KeyPartInfo *key_part;
 
290
  KEY_PART_INFO *key_part;
270
291
  const unsigned char *key_end= key + key_length;;
271
292
 
272
293
  for (key_part=table->key_info[idx].key_part;
278
299
 
279
300
    if (key_part->null_bit)
280
301
    {
281
 
      if (*key != test(table->getInsertRecord()[key_part->null_offset] &
 
302
      if (*key != test(table->record[0][key_part->null_offset] &
282
303
                       key_part->null_bit))
283
304
        return 1;
284
305
      if (*key)
293
314
        return 1;
294
315
      continue;
295
316
    }
296
 
    length= min((uint32_t) (key_end-key), store_length);
297
 
    if (key_part->field->type() == DRIZZLE_TYPE_VARCHAR)
 
317
    length= cmin((uint32_t) (key_end-key), store_length);
 
318
    if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
 
319
                                FIELDFLAG_PACK)))
298
320
    {
299
321
      const CHARSET_INFO * const cs= key_part->field->charset();
300
322
      uint32_t char_length= key_part->length / cs->mbmaxlen;
301
 
      const unsigned char *pos= table->getInsertRecord() + key_part->offset;
 
323
      const unsigned char *pos= table->record[0] + key_part->offset;
302
324
      if (length > char_length)
303
325
      {
304
326
        char_length= my_charpos(cs, pos, pos + length, char_length);
310
332
        return 1;
311
333
      continue;
312
334
    }
313
 
    if (memcmp(key,table->getInsertRecord()+key_part->offset,length))
 
335
    if (memcmp(key,table->record[0]+key_part->offset,length))
314
336
      return 1;
315
337
  }
316
338
  return 0;
330
352
     idx        Key number
331
353
*/
332
354
 
333
 
void key_unpack(String *to, const Table *table, uint32_t idx)
 
355
void key_unpack(String *to,Table *table,uint32_t idx)
334
356
{
335
 
  KeyPartInfo *key_part,*key_part_end;
 
357
  KEY_PART_INFO *key_part,*key_part_end;
336
358
  Field *field;
337
359
  String tmp;
338
360
 
346
368
      to->append('-');
347
369
    if (key_part->null_bit)
348
370
    {
349
 
      if (table->getInsertRecord()[key_part->null_offset] & key_part->null_bit)
 
371
      if (table->record[0][key_part->null_offset] & key_part->null_bit)
350
372
      {
351
373
        to->append(STRING_WITH_LEN("NULL"));
352
374
        continue;
353
375
      }
354
376
    }
355
 
    if ((field= key_part->field))
 
377
    if ((field=key_part->field))
356
378
    {
357
379
      const CHARSET_INFO * const cs= field->charset();
358
 
      field->setReadSet();
359
 
      field->val_str_internal(&tmp);
 
380
      field->val_str(&tmp);
360
381
      if (cs->mbmaxlen > 1 &&
361
 
          table->getField(key_part->fieldnr - 1)->field_length !=
 
382
          table->field[key_part->fieldnr - 1]->field_length !=
362
383
          key_part->length)
363
384
      {
364
385
        /*
376
397
      }
377
398
 
378
399
      if (key_part->length < field->pack_length())
379
 
        tmp.length(min(tmp.length(), static_cast<size_t>(key_part->length)));
 
400
        tmp.length(cmin(tmp.length(),(uint32_t)key_part->length));
380
401
      to->append(tmp);
381
402
    }
382
403
    else
383
404
      to->append(STRING_WITH_LEN("???"));
384
405
  }
 
406
 
 
407
  return;
385
408
}
386
409
 
387
410
 
403
426
    FALSE  Otherwise
404
427
*/
405
428
 
406
 
bool is_key_used(Table *table, uint32_t idx, const boost::dynamic_bitset<>& fields)
 
429
bool is_key_used(Table *table, uint32_t idx, const MY_BITMAP *fields)
407
430
{
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))
 
431
  bitmap_clear_all(&table->tmp_set);
 
432
  table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
 
433
  if (bitmap_is_overlapping(&table->tmp_set, fields))
411
434
    return 1;
412
435
 
413
436
  /*
414
437
    If table handler has primary key as part of the index, check that primary
415
438
    key is not updated
416
439
  */
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
 
  }
 
440
  if (idx != table->s->primary_key && table->s->primary_key < MAX_KEY &&
 
441
      (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
 
442
    return is_key_used(table, table->s->primary_key, fields);
422
443
  return 0;
423
444
}
424
445
 
427
448
  Compare key in row to a given key.
428
449
 
429
450
  @param key_part               Key part handler
430
 
  @param key                    Key to compare to value in table->getInsertRecord()
 
451
  @param key                    Key to compare to value in table->record[0]
431
452
  @param key_length             length of 'key'
432
453
 
433
454
  @return
437
458
    -   1               Key is larger than range
438
459
*/
439
460
 
440
 
int key_cmp(KeyPartInfo *key_part, const unsigned char *key, uint32_t key_length)
 
461
int key_cmp(KEY_PART_INFO *key_part, const unsigned char *key, uint32_t key_length)
441
462
{
442
463
  uint32_t store_length;
443
464
 
450
471
    if (key_part->null_bit)
451
472
    {
452
473
      /* This key part allows null values; NULL is lower than everything */
453
 
      bool field_is_null= key_part->field->is_null();
 
474
      register bool field_is_null= key_part->field->is_null();
454
475
      if (*key)                                 // If range key is null
455
476
      {
456
477
        /* the range is expecting a null value */
473
494
}
474
495
 
475
496
 
476
 
} /* namespace drizzled */
 
497
/*
 
498
  Compare two records in index order
 
499
  SYNOPSIS
 
500
    key_rec_cmp()
 
501
    key                         Index information
 
502
    rec0                        Pointer to table->record[0]
 
503
    first_rec                   Pointer to record compare with
 
504
    second_rec                  Pointer to record compare against first_rec
 
505
 
 
506
  DESCRIPTION
 
507
    This method is set-up such that it can be called directly from the
 
508
    priority queue and it is attempted to be optimised as much as possible
 
509
    since this will be called O(N * log N) times while performing a merge
 
510
    sort in various places in the code.
 
511
 
 
512
    We retrieve the pointer to table->record[0] using the fact that key_parts
 
513
    have an offset making it possible to calculate the start of the record.
 
514
    We need to get the diff to the compared record since none of the records
 
515
    being compared are stored in table->record[0].
 
516
 
 
517
    We first check for NULL values, if there are no NULL values we use
 
518
    a compare method that gets two field pointers and a max length
 
519
    and return the result of the comparison.
 
520
*/
 
521
 
 
522
int key_rec_cmp(void *key, unsigned char *first_rec, unsigned char *second_rec)
 
523
{
 
524
  KEY *key_info= (KEY*)key;
 
525
  uint32_t key_parts= key_info->key_parts, i= 0;
 
526
  KEY_PART_INFO *key_part= key_info->key_part;
 
527
  unsigned char *rec0= key_part->field->ptr - key_part->offset;
 
528
  my_ptrdiff_t first_diff= first_rec - rec0, sec_diff= second_rec - rec0;
 
529
  int result= 0;
 
530
 
 
531
  do
 
532
  {
 
533
    Field *field= key_part->field;
 
534
 
 
535
    if (key_part->null_bit)
 
536
    {
 
537
      /* The key_part can contain NULL values */
 
538
      bool first_is_null= field->is_null_in_record_with_offset(first_diff);
 
539
      bool sec_is_null= field->is_null_in_record_with_offset(sec_diff);
 
540
      /*
 
541
        NULL is smaller then everything so if first is NULL and the other
 
542
        not then we know that we should return -1 and for the opposite
 
543
        we should return +1. If both are NULL then we call it equality
 
544
        although it is a strange form of equality, we have equally little
 
545
        information of the real value.
 
546
      */
 
547
      if (!first_is_null)
 
548
      {
 
549
        if (!sec_is_null)
 
550
          ; /* Fall through, no NULL fields */
 
551
        else
 
552
        {
 
553
          return(1);
 
554
        }
 
555
      }
 
556
      else if (!sec_is_null)
 
557
      {
 
558
        return(-1);
 
559
      }
 
560
      else
 
561
        goto next_loop; /* Both were NULL */
 
562
    }
 
563
    /*
 
564
      No null values in the fields
 
565
      We use the virtual method cmp_max with a max length parameter.
 
566
      For most field types this translates into a cmp without
 
567
      max length. The exceptions are the BLOB and VARCHAR field types
 
568
      that take the max length into account.
 
569
    */
 
570
    result= field->cmp_max(field->ptr+first_diff, field->ptr+sec_diff,
 
571
                           key_part->length);
 
572
next_loop:
 
573
    key_part++;
 
574
  } while (!result && ++i < key_parts);
 
575
  return(result);
 
576
}