~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/key.cc

  • Committer: Monty Taylor
  • Date: 2008-08-01 22:33:44 UTC
  • mto: (236.1.42 codestyle)
  • mto: This revision was merged to the branch mainline in revision 261.
  • Revision ID: monty@inaugust.com-20080801223344-vzhlflfmtijp1imv
First pass at gettexizing the error messages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2006 MySQL AB
2
 
 
3
 
   This program is free software; you can redistribute it and/or modify
4
 
   it under the terms of the GNU General Public License as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
7
 
   This program is distributed in the hope that it will be useful,
8
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 
   GNU General Public License for more details.
11
 
 
12
 
   You should have received a copy of the GNU General Public License
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 */
15
 
 
16
 
 
17
 
/* Functions to handle keys and fields in forms */
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
 
{
36
 
 
37
 
/*
38
 
  Search after a key that starts with 'field'
39
 
 
40
 
  SYNOPSIS
41
 
    find_ref_key()
42
 
    key                 First key to check
43
 
    key_count           How many keys to check
44
 
    record              Start of record
45
 
    field               Field to search after
46
 
    key_length          On partial match, contains length of fields before
47
 
                        field
48
 
    keypart             key part # of a field
49
 
 
50
 
  NOTES
51
 
   Used when calculating key for NEXT_NUMBER
52
 
 
53
 
  IMPLEMENTATION
54
 
    If no key starts with field test if field is part of some key. If we find
55
 
    one, then return first key and set key_length to the number of bytes
56
 
    preceding 'field'.
57
 
 
58
 
  RETURN
59
 
   -1  field is not part of the key
60
 
   #   Key part for key matching key.
61
 
       key_length is set to length of key before (not including) field
62
 
*/
63
 
 
64
 
int find_ref_key(KeyInfo *key, uint32_t key_count, unsigned char *record, Field *field,
65
 
                 uint32_t *key_length, uint32_t *keypart)
66
 
{
67
 
  int i;
68
 
  KeyInfo *key_info;
69
 
  uint32_t fieldpos;
70
 
 
71
 
  fieldpos= field->offset(record);
72
 
 
73
 
  /* Test if some key starts as fieldpos */
74
 
  for (i= 0, key_info= key ;
75
 
       i < (int) key_count ;
76
 
       i++, key_info++)
77
 
  {
78
 
    if (key_info->key_part[0].offset == fieldpos)
79
 
    {                                           /* Found key. Calc keylength */
80
 
      *key_length= *keypart= 0;
81
 
      return i;                                 /* Use this key */
82
 
    }
83
 
  }
84
 
 
85
 
  /* Test if some key contains fieldpos */
86
 
  for (i= 0, key_info= key;
87
 
       i < (int) key_count ;
88
 
       i++, key_info++)
89
 
  {
90
 
    uint32_t j;
91
 
    KeyPartInfo *key_part;
92
 
    *key_length=0;
93
 
    for (j=0, key_part=key_info->key_part ;
94
 
         j < key_info->key_parts ;
95
 
         j++, key_part++)
96
 
    {
97
 
      if (key_part->offset == fieldpos)
98
 
      {
99
 
        *keypart= j;
100
 
        return i;                               /* Use this key */
101
 
      }
102
 
      *key_length+= key_part->store_length;
103
 
    }
104
 
  }
105
 
  return(-1);                                   /* No key is ok */
106
 
}
107
 
 
108
 
 
109
 
void key_copy(unsigned char *to_key, unsigned char *from_record, KeyInfo *key_info,
110
 
              unsigned int key_length)
111
 
{
112
 
  uint32_t length;
113
 
  KeyPartInfo *key_part;
114
 
 
115
 
  if (key_length == 0)
116
 
    key_length= key_info->key_length;
117
 
  for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
118
 
  {
119
 
    if (key_part->null_bit)
120
 
    {
121
 
      *to_key++= test(from_record[key_part->null_offset] &
122
 
                   key_part->null_bit);
123
 
      key_length--;
124
 
    }
125
 
    if (key_part->key_part_flag & HA_BLOB_PART ||
126
 
        key_part->key_part_flag & HA_VAR_LENGTH_PART)
127
 
    {
128
 
      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);
131
 
      to_key+= HA_KEY_BLOB_LENGTH;
132
 
    }
133
 
    else
134
 
    {
135
 
      length= min((uint16_t)key_length, key_part->length);
136
 
      Field *field= key_part->field;
137
 
      const CHARSET_INFO * const cs= field->charset();
138
 
      uint32_t bytes= field->get_key_image(to_key, length);
139
 
      if (bytes < length)
140
 
        cs->cset->fill(cs, (char*) to_key + bytes, length - bytes, ' ');
141
 
    }
142
 
    to_key+= length;
143
 
    key_length-= length;
144
 
  }
145
 
}
146
 
 
147
 
 
148
 
/**
149
 
  Zero the null components of key tuple.
150
 
*/
151
 
 
152
 
void key_zero_nulls(unsigned char *tuple, KeyInfo *key_info)
153
 
{
154
 
  KeyPartInfo *key_part= key_info->key_part;
155
 
  KeyPartInfo *key_part_end= key_part + key_info->key_parts;
156
 
  for (; key_part != key_part_end; key_part++)
157
 
  {
158
 
    if (key_part->null_bit && *tuple)
159
 
      memset(tuple+1, 0, key_part->store_length-1);
160
 
    tuple+= key_part->store_length;
161
 
  }
162
 
}
163
 
 
164
 
 
165
 
/*
166
 
  Restore a key from some buffer to record.
167
 
 
168
 
    This function converts a key into record format. It can be used in cases
169
 
    when we want to return a key as a result row.
170
 
 
171
 
  @param to_record   record buffer where the key will be restored to
172
 
  @param from_key    buffer that contains a key
173
 
  @param key_info    descriptor of the index
174
 
  @param key_length  specifies length of all keyparts that will be restored
175
 
*/
176
 
 
177
 
void key_restore(unsigned char *to_record, unsigned char *from_key, KeyInfo *key_info,
178
 
                 uint16_t key_length)
179
 
{
180
 
  uint32_t length;
181
 
  KeyPartInfo *key_part;
182
 
 
183
 
  if (key_length == 0)
184
 
  {
185
 
    key_length= key_info->key_length;
186
 
  }
187
 
  for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++)
188
 
  {
189
 
    unsigned char used_uneven_bits= 0;
190
 
    if (key_part->null_bit)
191
 
    {
192
 
      if (*from_key++)
193
 
        to_record[key_part->null_offset]|= key_part->null_bit;
194
 
      else
195
 
        to_record[key_part->null_offset]&= ~key_part->null_bit;
196
 
      key_length--;
197
 
    }
198
 
    if (key_part->key_part_flag & HA_BLOB_PART)
199
 
    {
200
 
      /*
201
 
        This in fact never happens, as we have only partial BLOB
202
 
        keys yet anyway, so it's difficult to find any sence to
203
 
        restore the part of a record.
204
 
        Maybe this branch is to be removed, but now we
205
 
        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
 
      */
209
 
      uint32_t blob_length= uint2korr(from_key);
210
 
      Field_blob *field= (Field_blob*) key_part->field;
211
 
 
212
 
      field->setReadSet();
213
 
      from_key+= HA_KEY_BLOB_LENGTH;
214
 
      key_length-= HA_KEY_BLOB_LENGTH;
215
 
      field->set_ptr_offset(to_record - field->getTable()->getInsertRecord(),
216
 
                            (ulong) blob_length, from_key);
217
 
      length= key_part->length;
218
 
    }
219
 
    else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
220
 
    {
221
 
      Field *field= key_part->field;
222
 
      ptrdiff_t ptrdiff= to_record - field->getTable()->getInsertRecord();
223
 
 
224
 
      field->setReadSet();
225
 
      field->setWriteSet();
226
 
      field->move_field_offset(ptrdiff);
227
 
      key_length-= HA_KEY_BLOB_LENGTH;
228
 
      length= min(key_length, key_part->length);
229
 
      field->set_key_image(from_key, length);
230
 
      from_key+= HA_KEY_BLOB_LENGTH;
231
 
      field->move_field_offset(-ptrdiff);
232
 
    }
233
 
    else
234
 
    {
235
 
      length= min(key_length, key_part->length);
236
 
      /* skip the byte with 'uneven' bits, if used */
237
 
      memcpy(to_record + key_part->offset, from_key + used_uneven_bits
238
 
             , (size_t) length - used_uneven_bits);
239
 
    }
240
 
    from_key+= length;
241
 
    key_length-= length;
242
 
  }
243
 
}
244
 
 
245
 
 
246
 
/**
247
 
  Compare if a key has changed.
248
 
 
249
 
  @param table          Table
250
 
  @param key            key to compare to row
251
 
  @param idx            Index used
252
 
  @param key_length     Length of key
253
 
 
254
 
  @note
255
 
    In theory we could just call field->cmp() for all field types,
256
 
    but as we are only interested if a key has changed (not if the key is
257
 
    larger or smaller than the previous value) we can do things a bit
258
 
    faster by using memcmp() instead.
259
 
 
260
 
  @retval
261
 
    0   If key is equal
262
 
  @retval
263
 
    1   Key has changed
264
 
*/
265
 
 
266
 
bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
267
 
{
268
 
  uint32_t store_length;
269
 
  KeyPartInfo *key_part;
270
 
  const unsigned char *key_end= key + key_length;;
271
 
 
272
 
  for (key_part=table->key_info[idx].key_part;
273
 
       key < key_end ;
274
 
       key_part++, key+= store_length)
275
 
  {
276
 
    uint32_t length;
277
 
    store_length= key_part->store_length;
278
 
 
279
 
    if (key_part->null_bit)
280
 
    {
281
 
      if (*key != test(table->getInsertRecord()[key_part->null_offset] &
282
 
                       key_part->null_bit))
283
 
        return 1;
284
 
      if (*key)
285
 
        continue;
286
 
      key++;
287
 
      store_length--;
288
 
    }
289
 
    if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART |
290
 
                                   HA_BIT_PART))
291
 
    {
292
 
      if (key_part->field->key_cmp(key, key_part->length))
293
 
        return 1;
294
 
      continue;
295
 
    }
296
 
    length= min((uint32_t) (key_end-key), store_length);
297
 
    if (key_part->field->type() == DRIZZLE_TYPE_VARCHAR)
298
 
    {
299
 
      const CHARSET_INFO * const cs= key_part->field->charset();
300
 
      uint32_t char_length= key_part->length / cs->mbmaxlen;
301
 
      const unsigned char *pos= table->getInsertRecord() + key_part->offset;
302
 
      if (length > char_length)
303
 
      {
304
 
        char_length= my_charpos(cs, pos, pos + length, char_length);
305
 
        set_if_smaller(char_length, length);
306
 
      }
307
 
      if (cs->coll->strnncollsp(cs,
308
 
                                (const unsigned char*) key, length,
309
 
                                (const unsigned char*) pos, char_length, 0))
310
 
        return 1;
311
 
      continue;
312
 
    }
313
 
    if (memcmp(key,table->getInsertRecord()+key_part->offset,length))
314
 
      return 1;
315
 
  }
316
 
  return 0;
317
 
}
318
 
 
319
 
/*
320
 
  unpack key-fields from record to some buffer.
321
 
 
322
 
  This is used mainly to get a good error message.  We temporary
323
 
  change the column bitmap so that all columns are readable.
324
 
 
325
 
  @param
326
 
     to         Store value here in an easy to read form
327
 
  @param
328
 
     table      Table to use
329
 
  @param
330
 
     idx        Key number
331
 
*/
332
 
 
333
 
void key_unpack(String *to, const Table *table, uint32_t idx)
334
 
{
335
 
  KeyPartInfo *key_part,*key_part_end;
336
 
  Field *field;
337
 
  String tmp;
338
 
 
339
 
  to->length(0);
340
 
  for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
341
 
         table->key_info[idx].key_parts ;
342
 
       key_part < key_part_end;
343
 
       key_part++)
344
 
  {
345
 
    if (to->length())
346
 
      to->append('-');
347
 
    if (key_part->null_bit)
348
 
    {
349
 
      if (table->getInsertRecord()[key_part->null_offset] & key_part->null_bit)
350
 
      {
351
 
        to->append(STRING_WITH_LEN("NULL"));
352
 
        continue;
353
 
      }
354
 
    }
355
 
    if ((field= key_part->field))
356
 
    {
357
 
      const CHARSET_INFO * const cs= field->charset();
358
 
      field->setReadSet();
359
 
      field->val_str_internal(&tmp);
360
 
      if (cs->mbmaxlen > 1 &&
361
 
          table->getField(key_part->fieldnr - 1)->field_length !=
362
 
          key_part->length)
363
 
      {
364
 
        /*
365
 
          Prefix key, multi-byte charset.
366
 
          For the columns of type CHAR(N), the above val_str()
367
 
          call will return exactly "key_part->length" bytes,
368
 
          which can break a multi-byte characters in the middle.
369
 
          Align, returning not more than "char_length" characters.
370
 
        */
371
 
        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(),
374
 
                                 char_length)) < key_part->length)
375
 
          tmp.length(charpos);
376
 
      }
377
 
 
378
 
      if (key_part->length < field->pack_length())
379
 
        tmp.length(min(tmp.length(), static_cast<size_t>(key_part->length)));
380
 
      to->append(tmp);
381
 
    }
382
 
    else
383
 
      to->append(STRING_WITH_LEN("???"));
384
 
  }
385
 
}
386
 
 
387
 
 
388
 
/*
389
 
  Check if key uses field that is marked in passed field bitmap.
390
 
 
391
 
  SYNOPSIS
392
 
    is_key_used()
393
 
      table   Table object with which keys and fields are associated.
394
 
      idx     Key to be checked.
395
 
      fields  Bitmap of fields to be checked.
396
 
 
397
 
  NOTE
398
 
    This function uses Table::tmp_set bitmap so the caller should care
399
 
    about saving/restoring its state if it also uses this bitmap.
400
 
 
401
 
  RETURN VALUE
402
 
    TRUE   Key uses field from bitmap
403
 
    FALSE  Otherwise
404
 
*/
405
 
 
406
 
bool is_key_used(Table *table, uint32_t idx, const boost::dynamic_bitset<>& fields)
407
 
{
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))
411
 
    return 1;
412
 
 
413
 
  /*
414
 
    If table handler has primary key as part of the index, check that primary
415
 
    key is not updated
416
 
  */
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
 
  }
422
 
  return 0;
423
 
}
424
 
 
425
 
 
426
 
/**
427
 
  Compare key in row to a given key.
428
 
 
429
 
  @param key_part               Key part handler
430
 
  @param key                    Key to compare to value in table->getInsertRecord()
431
 
  @param key_length             length of 'key'
432
 
 
433
 
  @return
434
 
    The return value is SIGN(key_in_row - range_key):
435
 
    -   0               Key is equal to range or 'range' == 0 (no range)
436
 
    -  -1               Key is less than range
437
 
    -   1               Key is larger than range
438
 
*/
439
 
 
440
 
int key_cmp(KeyPartInfo *key_part, const unsigned char *key, uint32_t key_length)
441
 
{
442
 
  uint32_t store_length;
443
 
 
444
 
  for (const unsigned char *end=key + key_length;
445
 
       key < end;
446
 
       key+= store_length, key_part++)
447
 
  {
448
 
    int cmp;
449
 
    store_length= key_part->store_length;
450
 
    if (key_part->null_bit)
451
 
    {
452
 
      /* This key part allows null values; NULL is lower than everything */
453
 
      bool field_is_null= key_part->field->is_null();
454
 
      if (*key)                                 // If range key is null
455
 
      {
456
 
        /* the range is expecting a null value */
457
 
        if (!field_is_null)
458
 
          return 1;                             // Found key is > range
459
 
        /* null -- exact match, go to next key part */
460
 
        continue;
461
 
      }
462
 
      else if (field_is_null)
463
 
        return -1;                              // NULL is less than any value
464
 
      key++;                                    // Skip null byte
465
 
      store_length--;
466
 
    }
467
 
    if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0)
468
 
      return -1;
469
 
    if (cmp > 0)
470
 
      return 1;
471
 
  }
472
 
  return 0;                                     // Keys are equal
473
 
}
474
 
 
475
 
 
476
 
} /* namespace drizzled */