~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/key.cc

  • Committer: Monty Taylor
  • Date: 2009-03-04 02:48:12 UTC
  • mto: (917.1.2 mordred)
  • mto: This revision was merged to the branch mainline in revision 918.
  • Revision ID: mordred@inaugust.com-20090304024812-5wb6wpye5c1iitbq
Applied atomic patch to current tree.

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
 
 
25
 
#include <boost/dynamic_bitset.hpp>
 
19
#include <drizzled/server_includes.h>
 
20
#include <drizzled/table.h>
 
21
#include <drizzled/field/blob.h>
26
22
 
27
23
#include <string>
28
24
 
29
 
#include <algorithm>
30
 
 
31
25
using namespace std;
32
26
 
33
 
namespace drizzled
34
 
{
35
 
 
36
27
/*
37
28
  Search after a key that starts with 'field'
38
29
 
60
51
       key_length is set to length of key before (not including) field
61
52
*/
62
53
 
63
 
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,
64
55
                 uint32_t *key_length, uint32_t *keypart)
65
56
{
66
57
  register int i;
67
 
  register KeyInfo *key_info;
 
58
  register KEY *key_info;
68
59
  uint32_t fieldpos;
69
60
 
70
61
  fieldpos= field->offset(record);
87
78
       i++, key_info++)
88
79
  {
89
80
    uint32_t j;
90
 
    KeyPartInfo *key_part;
 
81
    KEY_PART_INFO *key_part;
91
82
    *key_length=0;
92
83
    for (j=0, key_part=key_info->key_part ;
93
84
         j < key_info->key_parts ;
105
96
}
106
97
 
107
98
 
108
 
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,
109
100
              unsigned int key_length)
110
101
{
111
102
  uint32_t length;
112
 
  KeyPartInfo *key_part;
 
103
  KEY_PART_INFO *key_part;
113
104
 
114
105
  if (key_length == 0)
115
106
    key_length= key_info->key_length;
125
116
        key_part->key_part_flag & HA_VAR_LENGTH_PART)
126
117
    {
127
118
      key_length-= HA_KEY_BLOB_LENGTH;
128
 
      length= min((uint16_t)key_length, key_part->length);
129
 
      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);
130
121
      to_key+= HA_KEY_BLOB_LENGTH;
131
122
    }
132
123
    else
133
124
    {
134
 
      length= min((uint16_t)key_length, key_part->length);
 
125
      length= cmin((uint16_t)key_length, key_part->length);
135
126
      Field *field= key_part->field;
136
127
      const CHARSET_INFO * const cs= field->charset();
137
 
      uint32_t bytes= field->get_key_image(to_key, length);
 
128
      uint32_t bytes= field->get_key_image(to_key, length, Field::itRAW);
138
129
      if (bytes < length)
139
130
        cs->cset->fill(cs, (char*) to_key + bytes, length - bytes, ' ');
140
131
    }
144
135
}
145
136
 
146
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
 
147
176
/**
148
177
  Zero the null components of key tuple.
149
178
*/
150
179
 
151
 
void key_zero_nulls(unsigned char *tuple, KeyInfo *key_info)
 
180
void key_zero_nulls(unsigned char *tuple, KEY *key_info)
152
181
{
153
 
  KeyPartInfo *key_part= key_info->key_part;
154
 
  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;
155
184
  for (; key_part != key_part_end; key_part++)
156
185
  {
157
186
    if (key_part->null_bit && *tuple)
173
202
  @param key_length  specifies length of all keyparts that will be restored
174
203
*/
175
204
 
176
 
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,
177
206
                 uint16_t key_length)
178
207
{
179
208
  uint32_t length;
180
 
  KeyPartInfo *key_part;
 
209
  KEY_PART_INFO *key_part;
181
210
 
182
211
  if (key_length == 0)
183
212
  {
202
231
        restore the part of a record.
203
232
        Maybe this branch is to be removed, but now we
204
233
        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
234
      */
208
235
      uint32_t blob_length= uint2korr(from_key);
209
236
      Field_blob *field= (Field_blob*) key_part->field;
210
 
 
211
 
      field->setReadSet();
212
237
      from_key+= HA_KEY_BLOB_LENGTH;
213
238
      key_length-= HA_KEY_BLOB_LENGTH;
214
 
      field->set_ptr_offset(to_record - field->getTable()->getInsertRecord(),
 
239
      field->set_ptr_offset(to_record - field->table->record[0],
215
240
                            (ulong) blob_length, from_key);
216
241
      length= key_part->length;
217
242
    }
218
243
    else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
219
244
    {
220
245
      Field *field= key_part->field;
221
 
      ptrdiff_t ptrdiff= to_record - field->getTable()->getInsertRecord();
222
 
 
223
 
      field->setReadSet();
224
 
      field->setWriteSet();
 
246
      my_ptrdiff_t ptrdiff= to_record - field->table->record[0];
225
247
      field->move_field_offset(ptrdiff);
226
248
      key_length-= HA_KEY_BLOB_LENGTH;
227
 
      length= min(key_length, key_part->length);
 
249
      length= cmin(key_length, key_part->length);
228
250
      field->set_key_image(from_key, length);
229
251
      from_key+= HA_KEY_BLOB_LENGTH;
230
252
      field->move_field_offset(-ptrdiff);
231
253
    }
232
254
    else
233
255
    {
234
 
      length= min(key_length, key_part->length);
 
256
      length= cmin(key_length, key_part->length);
235
257
      /* skip the byte with 'uneven' bits, if used */
236
258
      memcpy(to_record + key_part->offset, from_key + used_uneven_bits
237
259
             , (size_t) length - used_uneven_bits);
265
287
bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
266
288
{
267
289
  uint32_t store_length;
268
 
  KeyPartInfo *key_part;
 
290
  KEY_PART_INFO *key_part;
269
291
  const unsigned char *key_end= key + key_length;;
270
292
 
271
293
  for (key_part=table->key_info[idx].key_part;
277
299
 
278
300
    if (key_part->null_bit)
279
301
    {
280
 
      if (*key != test(table->getInsertRecord()[key_part->null_offset] &
 
302
      if (*key != test(table->record[0][key_part->null_offset] &
281
303
                       key_part->null_bit))
282
304
        return 1;
283
305
      if (*key)
292
314
        return 1;
293
315
      continue;
294
316
    }
295
 
    length= min((uint32_t) (key_end-key), store_length);
296
 
    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)))
297
320
    {
298
321
      const CHARSET_INFO * const cs= key_part->field->charset();
299
322
      uint32_t char_length= key_part->length / cs->mbmaxlen;
300
 
      const unsigned char *pos= table->getInsertRecord() + key_part->offset;
 
323
      const unsigned char *pos= table->record[0] + key_part->offset;
301
324
      if (length > char_length)
302
325
      {
303
326
        char_length= my_charpos(cs, pos, pos + length, char_length);
309
332
        return 1;
310
333
      continue;
311
334
    }
312
 
    if (memcmp(key,table->getInsertRecord()+key_part->offset,length))
 
335
    if (memcmp(key,table->record[0]+key_part->offset,length))
313
336
      return 1;
314
337
  }
315
338
  return 0;
329
352
     idx        Key number
330
353
*/
331
354
 
332
 
void key_unpack(String *to, Table *table, uint32_t idx)
 
355
void key_unpack(String *to,Table *table,uint32_t idx)
333
356
{
334
 
  KeyPartInfo *key_part,*key_part_end;
 
357
  KEY_PART_INFO *key_part,*key_part_end;
335
358
  Field *field;
336
359
  String tmp;
337
360
 
345
368
      to->append('-');
346
369
    if (key_part->null_bit)
347
370
    {
348
 
      if (table->getInsertRecord()[key_part->null_offset] & key_part->null_bit)
 
371
      if (table->record[0][key_part->null_offset] & key_part->null_bit)
349
372
      {
350
373
        to->append(STRING_WITH_LEN("NULL"));
351
374
        continue;
352
375
      }
353
376
    }
354
 
    if ((field= key_part->field))
 
377
    if ((field=key_part->field))
355
378
    {
356
379
      const CHARSET_INFO * const cs= field->charset();
357
 
      field->setReadSet();
358
 
      field->val_str_internal(&tmp);
 
380
      field->val_str(&tmp);
359
381
      if (cs->mbmaxlen > 1 &&
360
 
          table->getField(key_part->fieldnr - 1)->field_length !=
 
382
          table->field[key_part->fieldnr - 1]->field_length !=
361
383
          key_part->length)
362
384
      {
363
385
        /*
375
397
      }
376
398
 
377
399
      if (key_part->length < field->pack_length())
378
 
        tmp.length(min(tmp.length(), static_cast<size_t>(key_part->length)));
 
400
        tmp.length(cmin(tmp.length(),(uint32_t)key_part->length));
379
401
      to->append(tmp);
380
402
    }
381
403
    else
382
404
      to->append(STRING_WITH_LEN("???"));
383
405
  }
 
406
 
 
407
  return;
384
408
}
385
409
 
386
410
 
402
426
    FALSE  Otherwise
403
427
*/
404
428
 
405
 
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)
406
430
{
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))
 
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))
410
434
    return 1;
411
435
 
412
436
  /*
413
437
    If table handler has primary key as part of the index, check that primary
414
438
    key is not updated
415
439
  */
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
 
  }
 
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);
421
443
  return 0;
422
444
}
423
445
 
426
448
  Compare key in row to a given key.
427
449
 
428
450
  @param key_part               Key part handler
429
 
  @param key                    Key to compare to value in table->getInsertRecord()
 
451
  @param key                    Key to compare to value in table->record[0]
430
452
  @param key_length             length of 'key'
431
453
 
432
454
  @return
436
458
    -   1               Key is larger than range
437
459
*/
438
460
 
439
 
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)
440
462
{
441
463
  uint32_t store_length;
442
464
 
472
494
}
473
495
 
474
496
 
475
 
} /* 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
}