~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/key.cc

  • Committer: Brian Aker
  • Date: 2009-12-18 18:31:01 UTC
  • mfrom: (1241.2.7 build)
  • Revision ID: brian@gaz-20091218183101-igqg1dtowpa0o70s
Fixed from Monty.

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
 
#include "drizzled/plugin/storage_engine.h"
25
 
 
26
 
#include <boost/dynamic_bitset.hpp>
27
23
 
28
24
#include <string>
29
25
 
31
27
 
32
28
using namespace std;
33
29
 
34
 
namespace drizzled
35
 
{
36
 
 
37
30
/*
38
31
  Search after a key that starts with 'field'
39
32
 
61
54
       key_length is set to length of key before (not including) field
62
55
*/
63
56
 
64
 
int find_ref_key(KeyInfo *key, uint32_t key_count, unsigned char *record, Field *field,
 
57
int find_ref_key(KEY *key, uint32_t key_count, unsigned char *record, Field *field,
65
58
                 uint32_t *key_length, uint32_t *keypart)
66
59
{
67
60
  register int i;
68
 
  register KeyInfo *key_info;
 
61
  register KEY *key_info;
69
62
  uint32_t fieldpos;
70
63
 
71
64
  fieldpos= field->offset(record);
88
81
       i++, key_info++)
89
82
  {
90
83
    uint32_t j;
91
 
    KeyPartInfo *key_part;
 
84
    KEY_PART_INFO *key_part;
92
85
    *key_length=0;
93
86
    for (j=0, key_part=key_info->key_part ;
94
87
         j < key_info->key_parts ;
106
99
}
107
100
 
108
101
 
109
 
void key_copy(unsigned char *to_key, unsigned char *from_record, KeyInfo *key_info,
 
102
void key_copy(unsigned char *to_key, unsigned char *from_record, KEY *key_info,
110
103
              unsigned int key_length)
111
104
{
112
105
  uint32_t length;
113
 
  KeyPartInfo *key_part;
 
106
  KEY_PART_INFO *key_part;
114
107
 
115
108
  if (key_length == 0)
116
109
    key_length= key_info->key_length;
149
142
  Zero the null components of key tuple.
150
143
*/
151
144
 
152
 
void key_zero_nulls(unsigned char *tuple, KeyInfo *key_info)
 
145
void key_zero_nulls(unsigned char *tuple, KEY *key_info)
153
146
{
154
 
  KeyPartInfo *key_part= key_info->key_part;
155
 
  KeyPartInfo *key_part_end= key_part + key_info->key_parts;
 
147
  KEY_PART_INFO *key_part= key_info->key_part;
 
148
  KEY_PART_INFO *key_part_end= key_part + key_info->key_parts;
156
149
  for (; key_part != key_part_end; key_part++)
157
150
  {
158
151
    if (key_part->null_bit && *tuple)
174
167
  @param key_length  specifies length of all keyparts that will be restored
175
168
*/
176
169
 
177
 
void key_restore(unsigned char *to_record, unsigned char *from_key, KeyInfo *key_info,
 
170
void key_restore(unsigned char *to_record, unsigned char *from_key, KEY *key_info,
178
171
                 uint16_t key_length)
179
172
{
180
173
  uint32_t length;
181
 
  KeyPartInfo *key_part;
 
174
  KEY_PART_INFO *key_part;
182
175
 
183
176
  if (key_length == 0)
184
177
  {
212
205
      field->setReadSet();
213
206
      from_key+= HA_KEY_BLOB_LENGTH;
214
207
      key_length-= HA_KEY_BLOB_LENGTH;
215
 
      field->set_ptr_offset(to_record - field->getTable()->getInsertRecord(),
 
208
      field->set_ptr_offset(to_record - field->table->record[0],
216
209
                            (ulong) blob_length, from_key);
217
210
      length= key_part->length;
218
211
    }
219
212
    else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
220
213
    {
221
214
      Field *field= key_part->field;
222
 
      ptrdiff_t ptrdiff= to_record - field->getTable()->getInsertRecord();
 
215
      ptrdiff_t ptrdiff= to_record - field->table->record[0];
223
216
 
224
217
      field->setReadSet();
225
218
      field->setWriteSet();
266
259
bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
267
260
{
268
261
  uint32_t store_length;
269
 
  KeyPartInfo *key_part;
 
262
  KEY_PART_INFO *key_part;
270
263
  const unsigned char *key_end= key + key_length;;
271
264
 
272
265
  for (key_part=table->key_info[idx].key_part;
278
271
 
279
272
    if (key_part->null_bit)
280
273
    {
281
 
      if (*key != test(table->getInsertRecord()[key_part->null_offset] &
 
274
      if (*key != test(table->record[0][key_part->null_offset] &
282
275
                       key_part->null_bit))
283
276
        return 1;
284
277
      if (*key)
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;
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;
356
349
    {
357
350
      const CHARSET_INFO * const cs= field->charset();
358
351
      field->setReadSet();
359
 
      field->val_str_internal(&tmp);
 
352
      field->val_str(&tmp);
360
353
      if (cs->mbmaxlen > 1 &&
361
 
          table->getField(key_part->fieldnr - 1)->field_length !=
 
354
          table->field[key_part->fieldnr - 1]->field_length !=
362
355
          key_part->length)
363
356
      {
364
357
        /*
376
369
      }
377
370
 
378
371
      if (key_part->length < field->pack_length())
379
 
        tmp.length(min(tmp.length(), static_cast<size_t>(key_part->length)));
 
372
        tmp.length(min(tmp.length(),(uint32_t)key_part->length));
380
373
      to->append(tmp);
381
374
    }
382
375
    else
403
396
    FALSE  Otherwise
404
397
*/
405
398
 
406
 
bool is_key_used(Table *table, uint32_t idx, const boost::dynamic_bitset<>& fields)
 
399
bool is_key_used(Table *table, uint32_t idx, const MyBitmap *fields)
407
400
{
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))
 
401
  table->tmp_set.clearAll();
 
402
  table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
 
403
  if (bitmap_is_overlapping(&table->tmp_set, fields))
411
404
    return 1;
412
405
 
413
406
  /*
414
407
    If table handler has primary key as part of the index, check that primary
415
408
    key is not updated
416
409
  */
417
 
  if (idx != table->getShare()->getPrimaryKey() && table->getShare()->hasPrimaryKey() &&
 
410
  if (idx != table->s->primary_key && table->s->primary_key < MAX_KEY &&
418
411
      (table->cursor->getEngine()->check_flag(HTON_BIT_PRIMARY_KEY_IN_READ_INDEX)))
419
 
  {
420
 
    return is_key_used(table, table->getShare()->getPrimaryKey(), fields);
421
 
  }
 
412
    return is_key_used(table, table->s->primary_key, fields);
422
413
  return 0;
423
414
}
424
415
 
427
418
  Compare key in row to a given key.
428
419
 
429
420
  @param key_part               Key part handler
430
 
  @param key                    Key to compare to value in table->getInsertRecord()
 
421
  @param key                    Key to compare to value in table->record[0]
431
422
  @param key_length             length of 'key'
432
423
 
433
424
  @return
437
428
    -   1               Key is larger than range
438
429
*/
439
430
 
440
 
int key_cmp(KeyPartInfo *key_part, const unsigned char *key, uint32_t key_length)
 
431
int key_cmp(KEY_PART_INFO *key_part, const unsigned char *key, uint32_t key_length)
441
432
{
442
433
  uint32_t store_length;
443
434
 
473
464
}
474
465
 
475
466
 
476
 
} /* namespace drizzled */
 
467
/*
 
468
  Compare two records in index order
 
469
  SYNOPSIS
 
470
    key_rec_cmp()
 
471
    key                         Index information
 
472
    rec0                        Pointer to table->record[0]
 
473
    first_rec                   Pointer to record compare with
 
474
    second_rec                  Pointer to record compare against first_rec
 
475
 
 
476
  DESCRIPTION
 
477
    This method is set-up such that it can be called directly from the
 
478
    priority queue and it is attempted to be optimised as much as possible
 
479
    since this will be called O(N * log N) times while performing a merge
 
480
    sort in various places in the code.
 
481
 
 
482
    We retrieve the pointer to table->record[0] using the fact that key_parts
 
483
    have an offset making it possible to calculate the start of the record.
 
484
    We need to get the diff to the compared record since none of the records
 
485
    being compared are stored in table->record[0].
 
486
 
 
487
    We first check for NULL values, if there are no NULL values we use
 
488
    a compare method that gets two field pointers and a max length
 
489
    and return the result of the comparison.
 
490
*/
 
491
 
 
492
int key_rec_cmp(void *key, unsigned char *first_rec, unsigned char *second_rec)
 
493
{
 
494
  KEY *key_info= (KEY*)key;
 
495
  uint32_t key_parts= key_info->key_parts, i= 0;
 
496
  KEY_PART_INFO *key_part= key_info->key_part;
 
497
  unsigned char *rec0= key_part->field->ptr - key_part->offset;
 
498
  ptrdiff_t first_diff= first_rec - rec0, sec_diff= second_rec - rec0;
 
499
  int result= 0;
 
500
 
 
501
  do
 
502
  {
 
503
    Field *field= key_part->field;
 
504
 
 
505
    if (key_part->null_bit)
 
506
    {
 
507
      /* The key_part can contain NULL values */
 
508
      bool first_is_null= field->is_null_in_record_with_offset(first_diff);
 
509
      bool sec_is_null= field->is_null_in_record_with_offset(sec_diff);
 
510
      /*
 
511
        NULL is smaller then everything so if first is NULL and the other
 
512
        not then we know that we should return -1 and for the opposite
 
513
        we should return +1. If both are NULL then we call it equality
 
514
        although it is a strange form of equality, we have equally little
 
515
        information of the real value.
 
516
      */
 
517
      if (!first_is_null)
 
518
      {
 
519
        if (!sec_is_null)
 
520
          ; /* Fall through, no NULL fields */
 
521
        else
 
522
        {
 
523
          return(1);
 
524
        }
 
525
      }
 
526
      else if (!sec_is_null)
 
527
      {
 
528
        return(-1);
 
529
      }
 
530
      else
 
531
        goto next_loop; /* Both were NULL */
 
532
    }
 
533
    /*
 
534
      No null values in the fields
 
535
      We use the virtual method cmp_max with a max length parameter.
 
536
      For most field types this translates into a cmp without
 
537
      max length. The exceptions are the BLOB and VARCHAR field types
 
538
      that take the max length into account.
 
539
    */
 
540
    result= field->cmp_max(field->ptr+first_diff, field->ptr+sec_diff,
 
541
                           key_part->length);
 
542
next_loop:
 
543
    key_part++;
 
544
  } while (!result && ++i < key_parts);
 
545
  return(result);
 
546
}