~drizzle-trunk/drizzle/development

1 by brian
clean slate
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
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
14
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
1 by brian
clean slate
15
16
17
/* Functions to handle keys and fields in forms */
18
2173.2.1 by Monty Taylor
Fixes incorrect usage of include
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>
1 by brian
clean slate
25
1802.16.5 by Padraig O'Sullivan
Adding help method for dynamic bitset functions. Temporary until MyBitmap is removed. Got rid of another MyBitmap usage in the range optimizer.
26
#include <boost/dynamic_bitset.hpp>
27
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
28
#include <string>
29
1067.4.4 by Nathan Williams
The rest of the files in the drizzled directory were purged of the cmin macro and replace with std::min (except for the definition in globals.h and 1 usage in stacktrace.cc).
30
#include <algorithm>
31
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
32
using namespace std;
33
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
34
namespace drizzled
35
{
36
1 by brian
clean slate
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
1535 by Brian Aker
Rename of KEY to KeyInfo
64
int find_ref_key(KeyInfo *key, uint32_t key_count, unsigned char *record, Field *field,
482 by Brian Aker
Remove uint.
65
                 uint32_t *key_length, uint32_t *keypart)
1 by brian
clean slate
66
{
2170.5.2 by Olaf van der Spek
more
67
  int i;
68
  KeyInfo *key_info;
482 by Brian Aker
Remove uint.
69
  uint32_t fieldpos;
1 by brian
clean slate
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
  {
482 by Brian Aker
Remove uint.
90
    uint32_t j;
1534 by Brian Aker
Remove of KeyPartInfo
91
    KeyPartInfo *key_part;
1 by brian
clean slate
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
1535 by Brian Aker
Rename of KEY to KeyInfo
109
void key_copy(unsigned char *to_key, unsigned char *from_record, KeyInfo *key_info,
287.3.8 by Monty Taylor
Oy. Replaced max and min macros with std::max and std::min so that we get
110
              unsigned int key_length)
1 by brian
clean slate
111
{
482 by Brian Aker
Remove uint.
112
  uint32_t length;
1534 by Brian Aker
Remove of KeyPartInfo
113
  KeyPartInfo *key_part;
1 by brian
clean slate
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;
1067.4.4 by Nathan Williams
The rest of the files in the drizzled directory were purged of the cmin macro and replace with std::min (except for the definition in globals.h and 1 usage in stacktrace.cc).
129
      length= min((uint16_t)key_length, key_part->length);
1055.2.5 by Jay Pipes
Removal of dead Field::image_type and st_key_part::image_type member variables. Legacy from geometry MyISAM types...
130
      key_part->field->get_key_image(to_key, length);
1 by brian
clean slate
131
      to_key+= HA_KEY_BLOB_LENGTH;
132
    }
133
    else
134
    {
1067.4.4 by Nathan Williams
The rest of the files in the drizzled directory were purged of the cmin macro and replace with std::min (except for the definition in globals.h and 1 usage in stacktrace.cc).
135
      length= min((uint16_t)key_length, key_part->length);
1 by brian
clean slate
136
      Field *field= key_part->field;
2254 by Brian Aker
Shift CHARSET_INFO to charset_info_st
137
      const charset_info_st * const cs= field->charset();
1055.2.5 by Jay Pipes
Removal of dead Field::image_type and st_key_part::image_type member variables. Legacy from geometry MyISAM types...
138
      uint32_t bytes= field->get_key_image(to_key, length);
1 by brian
clean slate
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
1535 by Brian Aker
Rename of KEY to KeyInfo
152
void key_zero_nulls(unsigned char *tuple, KeyInfo *key_info)
1 by brian
clean slate
153
{
1534 by Brian Aker
Remove of KeyPartInfo
154
  KeyPartInfo *key_part= key_info->key_part;
155
  KeyPartInfo *key_part_end= key_part + key_info->key_parts;
1 by brian
clean slate
156
  for (; key_part != key_part_end; key_part++)
157
  {
158
    if (key_part->null_bit && *tuple)
212.6.1 by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file.
159
      memset(tuple+1, 0, key_part->store_length-1);
1 by brian
clean slate
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
1535 by Brian Aker
Rename of KEY to KeyInfo
177
void key_restore(unsigned char *to_record, unsigned char *from_key, KeyInfo *key_info,
287.3.8 by Monty Taylor
Oy. Replaced max and min macros with std::max and std::min so that we get
178
                 uint16_t key_length)
1 by brian
clean slate
179
{
482 by Brian Aker
Remove uint.
180
  uint32_t length;
1534 by Brian Aker
Remove of KeyPartInfo
181
  KeyPartInfo *key_part;
1 by brian
clean slate
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
  {
481 by Brian Aker
Remove all of uchar.
189
    unsigned char used_uneven_bits= 0;
1 by brian
clean slate
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.
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
206
207
        This may make more sense once we push down block lengths to the engine (aka partial retrieval).
1 by brian
clean slate
208
      */
482 by Brian Aker
Remove uint.
209
      uint32_t blob_length= uint2korr(from_key);
1 by brian
clean slate
210
      Field_blob *field= (Field_blob*) key_part->field;
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
211
212
      field->setReadSet();
1 by brian
clean slate
213
      from_key+= HA_KEY_BLOB_LENGTH;
214
      key_length-= HA_KEY_BLOB_LENGTH;
1672.3.6 by Brian Aker
First pass in encapsulating row
215
      field->set_ptr_offset(to_record - field->getTable()->getInsertRecord(),
1 by brian
clean slate
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;
1672.3.6 by Brian Aker
First pass in encapsulating row
222
      ptrdiff_t ptrdiff= to_record - field->getTable()->getInsertRecord();
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
223
224
      field->setReadSet();
225
      field->setWriteSet();
1 by brian
clean slate
226
      field->move_field_offset(ptrdiff);
227
      key_length-= HA_KEY_BLOB_LENGTH;
1067.4.4 by Nathan Williams
The rest of the files in the drizzled directory were purged of the cmin macro and replace with std::min (except for the definition in globals.h and 1 usage in stacktrace.cc).
228
      length= min(key_length, key_part->length);
1 by brian
clean slate
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
    {
1067.4.4 by Nathan Williams
The rest of the files in the drizzled directory were purged of the cmin macro and replace with std::min (except for the definition in globals.h and 1 usage in stacktrace.cc).
235
      length= min(key_length, key_part->length);
1 by brian
clean slate
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
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
249
  @param table		Table
1 by brian
clean slate
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
482 by Brian Aker
Remove uint.
266
bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
1 by brian
clean slate
267
{
482 by Brian Aker
Remove uint.
268
  uint32_t store_length;
1534 by Brian Aker
Remove of KeyPartInfo
269
  KeyPartInfo *key_part;
481 by Brian Aker
Remove all of uchar.
270
  const unsigned char *key_end= key + key_length;;
1 by brian
clean slate
271
272
  for (key_part=table->key_info[idx].key_part;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
273
       key < key_end ;
1 by brian
clean slate
274
       key_part++, key+= store_length)
275
  {
482 by Brian Aker
Remove uint.
276
    uint32_t length;
1 by brian
clean slate
277
    store_length= key_part->store_length;
278
279
    if (key_part->null_bit)
280
    {
1672.3.6 by Brian Aker
First pass in encapsulating row
281
      if (*key != test(table->getInsertRecord()[key_part->null_offset] &
1 by brian
clean slate
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
    }
1067.4.4 by Nathan Williams
The rest of the files in the drizzled directory were purged of the cmin macro and replace with std::min (except for the definition in globals.h and 1 usage in stacktrace.cc).
296
    length= min((uint32_t) (key_end-key), store_length);
1119.9.5 by Jay Pipes
Removes FIELDFLAG_NUMBER, f_is_num() and f_is_alpha() macros. Buh bye.
297
    if (key_part->field->type() == DRIZZLE_TYPE_VARCHAR)
1 by brian
clean slate
298
    {
2254 by Brian Aker
Shift CHARSET_INFO to charset_info_st
299
      const charset_info_st * const cs= key_part->field->charset();
482 by Brian Aker
Remove uint.
300
      uint32_t char_length= key_part->length / cs->mbmaxlen;
1672.3.6 by Brian Aker
First pass in encapsulating row
301
      const unsigned char *pos= table->getInsertRecord() + key_part->offset;
1 by brian
clean slate
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,
481 by Brian Aker
Remove all of uchar.
308
                                (const unsigned char*) key, length,
309
                                (const unsigned char*) pos, char_length, 0))
1 by brian
clean slate
310
        return 1;
311
      continue;
312
    }
1672.3.6 by Brian Aker
First pass in encapsulating row
313
    if (memcmp(key,table->getInsertRecord()+key_part->offset,length))
1 by brian
clean slate
314
      return 1;
315
  }
316
  return 0;
317
}
318
319
/*
320
  unpack key-fields from record to some buffer.
321
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
322
  This is used mainly to get a good error message.  We temporary
1 by brian
clean slate
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
2148.7.12 by Brian Aker
Merge in header fixes.
333
void key_unpack(String *to, const Table *table, uint32_t idx)
1 by brian
clean slate
334
{
1534 by Brian Aker
Remove of KeyPartInfo
335
  KeyPartInfo *key_part,*key_part_end;
1 by brian
clean slate
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
    {
1672.3.6 by Brian Aker
First pass in encapsulating row
349
      if (table->getInsertRecord()[key_part->null_offset] & key_part->null_bit)
1 by brian
clean slate
350
      {
351
	to->append(STRING_WITH_LEN("NULL"));
352
	continue;
353
      }
354
    }
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
355
    if ((field= key_part->field))
1 by brian
clean slate
356
    {
2254 by Brian Aker
Shift CHARSET_INFO to charset_info_st
357
      const charset_info_st * const cs= field->charset();
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
358
      field->setReadSet();
1996.2.1 by Brian Aker
uuid type code.
359
      field->val_str_internal(&tmp);
1 by brian
clean slate
360
      if (cs->mbmaxlen > 1 &&
1578.2.16 by Brian Aker
Merge in change to getTable() to private the field objects.
361
          table->getField(key_part->fieldnr - 1)->field_length !=
1 by brian
clean slate
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
        */
482 by Brian Aker
Remove uint.
371
        uint32_t charpos, char_length= key_part->length / cs->mbmaxlen;
813.1.3 by Jay Pipes
Incorrectly passing str.ptr() instead of str.c_ptr() to my_charpos() in key.cc:key_unpack(). This resulted in duplicate key error messages containing random characters due to a bad offset, and would show up as random failure in the myisam.test case when running make test but not ./dtr myisam.
372
        if ((charpos= my_charpos(cs, tmp.c_ptr(),
373
                                 tmp.c_ptr() + tmp.length(),
1 by brian
clean slate
374
                                 char_length)) < key_part->length)
375
          tmp.length(charpos);
376
      }
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
377
1 by brian
clean slate
378
      if (key_part->length < field->pack_length())
1816.3.1 by Brian Aker
Convert sql_string to use size_t (this should clean up ICC warnings).
379
        tmp.length(min(tmp.length(), static_cast<size_t>(key_part->length)));
1 by brian
clean slate
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()
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
393
      table   Table object with which keys and fields are associated.
1 by brian
clean slate
394
      idx     Key to be checked.
395
      fields  Bitmap of fields to be checked.
396
397
  NOTE
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
398
    This function uses Table::tmp_set bitmap so the caller should care
1 by brian
clean slate
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
1802.16.5 by Padraig O'Sullivan
Adding help method for dynamic bitset functions. Temporary until MyBitmap is removed. Got rid of another MyBitmap usage in the range optimizer.
406
bool is_key_used(Table *table, uint32_t idx, const boost::dynamic_bitset<>& fields)
407
{
1802.16.8 by Padraig O'Sullivan
Removal of all MyBitmap from the code base. Compiles but test failures exist now.
408
  table->tmp_set.reset();
409
  table->mark_columns_used_by_index_no_reset(idx, table->tmp_set);
1802.16.11 by Padraig O'Sullivan
Remove cpp and header file with MyBitmap class and associated functions. No longer needed.
410
  if (table->tmp_set.is_subset_of(fields))
1802.16.5 by Padraig O'Sullivan
Adding help method for dynamic bitset functions. Temporary until MyBitmap is removed. Got rid of another MyBitmap usage in the range optimizer.
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
1 by brian
clean slate
426
/**
427
  Compare key in row to a given key.
428
429
  @param key_part		Key part handler
1672.3.6 by Brian Aker
First pass in encapsulating row
430
  @param key			Key to compare to value in table->getInsertRecord()
1 by brian
clean slate
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
1534 by Brian Aker
Remove of KeyPartInfo
440
int key_cmp(KeyPartInfo *key_part, const unsigned char *key, uint32_t key_length)
1 by brian
clean slate
441
{
482 by Brian Aker
Remove uint.
442
  uint32_t store_length;
1 by brian
clean slate
443
481 by Brian Aker
Remove all of uchar.
444
  for (const unsigned char *end=key + key_length;
1 by brian
clean slate
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 */
2170.5.2 by Olaf van der Spek
more
453
      bool field_is_null= key_part->field->is_null();
1 by brian
clean slate
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
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
476
} /* namespace drizzled */