~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
1241.9.36 by Monty Taylor
ZOMG. I deleted drizzled/server_includes.h.
19
#include "config.h"
934.2.21 by Jay Pipes
Move Key stuff into key.cc and out of session.cc
20
#include "drizzled/table.h"
21
#include "drizzled/key.h"
22
#include "drizzled/field/blob.h"
1802.16.11 by Padraig O'Sullivan
Remove cpp and header file with MyBitmap class and associated functions. No longer needed.
23
#include "drizzled/util/test.h"
1 by brian
clean slate
24
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.
25
#include <boost/dynamic_bitset.hpp>
26
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
27
#include <string>
28
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).
29
#include <algorithm>
30
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
31
using namespace std;
32
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
33
namespace drizzled
34
{
35
1 by brian
clean slate
36
/*
37
  Search after a key that starts with 'field'
38
39
  SYNOPSIS
40
    find_ref_key()
41
    key			First key to check
42
    key_count		How many keys to check
43
    record		Start of record
44
    field		Field to search after
45
    key_length		On partial match, contains length of fields before
46
			field
47
    keypart             key part # of a field
48
49
  NOTES
50
   Used when calculating key for NEXT_NUMBER
51
52
  IMPLEMENTATION
53
    If no key starts with field test if field is part of some key. If we find
54
    one, then return first key and set key_length to the number of bytes
55
    preceding 'field'.
56
57
  RETURN
58
   -1  field is not part of the key
59
   #   Key part for key matching key.
60
       key_length is set to length of key before (not including) field
61
*/
62
1535 by Brian Aker
Rename of KEY to KeyInfo
63
int find_ref_key(KeyInfo *key, uint32_t key_count, unsigned char *record, Field *field,
482 by Brian Aker
Remove uint.
64
                 uint32_t *key_length, uint32_t *keypart)
1 by brian
clean slate
65
{
66
  register int i;
1535 by Brian Aker
Rename of KEY to KeyInfo
67
  register KeyInfo *key_info;
482 by Brian Aker
Remove uint.
68
  uint32_t fieldpos;
1 by brian
clean slate
69
70
  fieldpos= field->offset(record);
71
72
  /* Test if some key starts as fieldpos */
73
  for (i= 0, key_info= key ;
74
       i < (int) key_count ;
75
       i++, key_info++)
76
  {
77
    if (key_info->key_part[0].offset == fieldpos)
78
    {                                  		/* Found key. Calc keylength */
79
      *key_length= *keypart= 0;
80
      return i;                                 /* Use this key */
81
    }
82
  }
83
84
  /* Test if some key contains fieldpos */
85
  for (i= 0, key_info= key;
86
       i < (int) key_count ;
87
       i++, key_info++)
88
  {
482 by Brian Aker
Remove uint.
89
    uint32_t j;
1534 by Brian Aker
Remove of KeyPartInfo
90
    KeyPartInfo *key_part;
1 by brian
clean slate
91
    *key_length=0;
92
    for (j=0, key_part=key_info->key_part ;
93
	 j < key_info->key_parts ;
94
	 j++, key_part++)
95
    {
96
      if (key_part->offset == fieldpos)
97
      {
98
        *keypart= j;
99
        return i;                               /* Use this key */
100
      }
101
      *key_length+= key_part->store_length;
102
    }
103
  }
104
  return(-1);					/* No key is ok */
105
}
106
107
1535 by Brian Aker
Rename of KEY to KeyInfo
108
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
109
              unsigned int key_length)
1 by brian
clean slate
110
{
482 by Brian Aker
Remove uint.
111
  uint32_t length;
1534 by Brian Aker
Remove of KeyPartInfo
112
  KeyPartInfo *key_part;
1 by brian
clean slate
113
114
  if (key_length == 0)
115
    key_length= key_info->key_length;
116
  for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
117
  {
118
    if (key_part->null_bit)
119
    {
120
      *to_key++= test(from_record[key_part->null_offset] &
121
		   key_part->null_bit);
122
      key_length--;
123
    }
124
    if (key_part->key_part_flag & HA_BLOB_PART ||
125
        key_part->key_part_flag & HA_VAR_LENGTH_PART)
126
    {
127
      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).
128
      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...
129
      key_part->field->get_key_image(to_key, length);
1 by brian
clean slate
130
      to_key+= HA_KEY_BLOB_LENGTH;
131
    }
132
    else
133
    {
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).
134
      length= min((uint16_t)key_length, key_part->length);
1 by brian
clean slate
135
      Field *field= key_part->field;
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
136
      const CHARSET_INFO * 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...
137
      uint32_t bytes= field->get_key_image(to_key, length);
1 by brian
clean slate
138
      if (bytes < length)
139
        cs->cset->fill(cs, (char*) to_key + bytes, length - bytes, ' ');
140
    }
141
    to_key+= length;
142
    key_length-= length;
143
  }
144
}
145
146
147
/**
148
  Zero the null components of key tuple.
149
*/
150
1535 by Brian Aker
Rename of KEY to KeyInfo
151
void key_zero_nulls(unsigned char *tuple, KeyInfo *key_info)
1 by brian
clean slate
152
{
1534 by Brian Aker
Remove of KeyPartInfo
153
  KeyPartInfo *key_part= key_info->key_part;
154
  KeyPartInfo *key_part_end= key_part + key_info->key_parts;
1 by brian
clean slate
155
  for (; key_part != key_part_end; key_part++)
156
  {
157
    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.
158
      memset(tuple+1, 0, key_part->store_length-1);
1 by brian
clean slate
159
    tuple+= key_part->store_length;
160
  }
161
}
162
163
164
/*
165
  Restore a key from some buffer to record.
166
167
    This function converts a key into record format. It can be used in cases
168
    when we want to return a key as a result row.
169
170
  @param to_record   record buffer where the key will be restored to
171
  @param from_key    buffer that contains a key
172
  @param key_info    descriptor of the index
173
  @param key_length  specifies length of all keyparts that will be restored
174
*/
175
1535 by Brian Aker
Rename of KEY to KeyInfo
176
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
177
                 uint16_t key_length)
1 by brian
clean slate
178
{
482 by Brian Aker
Remove uint.
179
  uint32_t length;
1534 by Brian Aker
Remove of KeyPartInfo
180
  KeyPartInfo *key_part;
1 by brian
clean slate
181
182
  if (key_length == 0)
183
  {
184
    key_length= key_info->key_length;
185
  }
186
  for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++)
187
  {
481 by Brian Aker
Remove all of uchar.
188
    unsigned char used_uneven_bits= 0;
1 by brian
clean slate
189
    if (key_part->null_bit)
190
    {
191
      if (*from_key++)
192
	to_record[key_part->null_offset]|= key_part->null_bit;
193
      else
194
	to_record[key_part->null_offset]&= ~key_part->null_bit;
195
      key_length--;
196
    }
197
    if (key_part->key_part_flag & HA_BLOB_PART)
198
    {
199
      /*
200
        This in fact never happens, as we have only partial BLOB
201
        keys yet anyway, so it's difficult to find any sence to
202
        restore the part of a record.
203
        Maybe this branch is to be removed, but now we
204
        have to ignore GCov compaining.
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
205
206
        This may make more sense once we push down block lengths to the engine (aka partial retrieval).
1 by brian
clean slate
207
      */
482 by Brian Aker
Remove uint.
208
      uint32_t blob_length= uint2korr(from_key);
1 by brian
clean slate
209
      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
210
211
      field->setReadSet();
1 by brian
clean slate
212
      from_key+= HA_KEY_BLOB_LENGTH;
213
      key_length-= HA_KEY_BLOB_LENGTH;
1672.3.6 by Brian Aker
First pass in encapsulating row
214
      field->set_ptr_offset(to_record - field->getTable()->getInsertRecord(),
1 by brian
clean slate
215
                            (ulong) blob_length, from_key);
216
      length= key_part->length;
217
    }
218
    else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
219
    {
220
      Field *field= key_part->field;
1672.3.6 by Brian Aker
First pass in encapsulating row
221
      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
222
223
      field->setReadSet();
224
      field->setWriteSet();
1 by brian
clean slate
225
      field->move_field_offset(ptrdiff);
226
      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).
227
      length= min(key_length, key_part->length);
1 by brian
clean slate
228
      field->set_key_image(from_key, length);
229
      from_key+= HA_KEY_BLOB_LENGTH;
230
      field->move_field_offset(-ptrdiff);
231
    }
232
    else
233
    {
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).
234
      length= min(key_length, key_part->length);
1 by brian
clean slate
235
      /* skip the byte with 'uneven' bits, if used */
236
      memcpy(to_record + key_part->offset, from_key + used_uneven_bits
237
             , (size_t) length - used_uneven_bits);
238
    }
239
    from_key+= length;
240
    key_length-= length;
241
  }
242
}
243
244
245
/**
246
  Compare if a key has changed.
247
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
248
  @param table		Table
1 by brian
clean slate
249
  @param key		key to compare to row
250
  @param idx		Index used
251
  @param key_length	Length of key
252
253
  @note
254
    In theory we could just call field->cmp() for all field types,
255
    but as we are only interested if a key has changed (not if the key is
256
    larger or smaller than the previous value) we can do things a bit
257
    faster by using memcmp() instead.
258
259
  @retval
260
    0	If key is equal
261
  @retval
262
    1	Key has changed
263
*/
264
482 by Brian Aker
Remove uint.
265
bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
1 by brian
clean slate
266
{
482 by Brian Aker
Remove uint.
267
  uint32_t store_length;
1534 by Brian Aker
Remove of KeyPartInfo
268
  KeyPartInfo *key_part;
481 by Brian Aker
Remove all of uchar.
269
  const unsigned char *key_end= key + key_length;;
1 by brian
clean slate
270
271
  for (key_part=table->key_info[idx].key_part;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
272
       key < key_end ;
1 by brian
clean slate
273
       key_part++, key+= store_length)
274
  {
482 by Brian Aker
Remove uint.
275
    uint32_t length;
1 by brian
clean slate
276
    store_length= key_part->store_length;
277
278
    if (key_part->null_bit)
279
    {
1672.3.6 by Brian Aker
First pass in encapsulating row
280
      if (*key != test(table->getInsertRecord()[key_part->null_offset] &
1 by brian
clean slate
281
		       key_part->null_bit))
282
	return 1;
283
      if (*key)
284
	continue;
285
      key++;
286
      store_length--;
287
    }
288
    if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART |
289
                                   HA_BIT_PART))
290
    {
291
      if (key_part->field->key_cmp(key, key_part->length))
292
	return 1;
293
      continue;
294
    }
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).
295
    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.
296
    if (key_part->field->type() == DRIZZLE_TYPE_VARCHAR)
1 by brian
clean slate
297
    {
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
298
      const CHARSET_INFO * const cs= key_part->field->charset();
482 by Brian Aker
Remove uint.
299
      uint32_t char_length= key_part->length / cs->mbmaxlen;
1672.3.6 by Brian Aker
First pass in encapsulating row
300
      const unsigned char *pos= table->getInsertRecord() + key_part->offset;
1 by brian
clean slate
301
      if (length > char_length)
302
      {
303
        char_length= my_charpos(cs, pos, pos + length, char_length);
304
        set_if_smaller(char_length, length);
305
      }
306
      if (cs->coll->strnncollsp(cs,
481 by Brian Aker
Remove all of uchar.
307
                                (const unsigned char*) key, length,
308
                                (const unsigned char*) pos, char_length, 0))
1 by brian
clean slate
309
        return 1;
310
      continue;
311
    }
1672.3.6 by Brian Aker
First pass in encapsulating row
312
    if (memcmp(key,table->getInsertRecord()+key_part->offset,length))
1 by brian
clean slate
313
      return 1;
314
  }
315
  return 0;
316
}
317
318
/*
319
  unpack key-fields from record to some buffer.
320
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
321
  This is used mainly to get a good error message.  We temporary
1 by brian
clean slate
322
  change the column bitmap so that all columns are readable.
323
324
  @param
325
     to		Store value here in an easy to read form
326
  @param
327
     table	Table to use
328
  @param
329
     idx	Key number
330
*/
331
1216.1.1 by Brian Aker
Move print_error up to Engine.
332
void key_unpack(String *to, Table *table, uint32_t idx)
1 by brian
clean slate
333
{
1534 by Brian Aker
Remove of KeyPartInfo
334
  KeyPartInfo *key_part,*key_part_end;
1 by brian
clean slate
335
  Field *field;
336
  String tmp;
337
338
  to->length(0);
339
  for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
340
	 table->key_info[idx].key_parts ;
341
       key_part < key_part_end;
342
       key_part++)
343
  {
344
    if (to->length())
345
      to->append('-');
346
    if (key_part->null_bit)
347
    {
1672.3.6 by Brian Aker
First pass in encapsulating row
348
      if (table->getInsertRecord()[key_part->null_offset] & key_part->null_bit)
1 by brian
clean slate
349
      {
350
	to->append(STRING_WITH_LEN("NULL"));
351
	continue;
352
      }
353
    }
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
354
    if ((field= key_part->field))
1 by brian
clean slate
355
    {
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
356
      const CHARSET_INFO * const cs= field->charset();
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
357
      field->setReadSet();
1 by brian
clean slate
358
      field->val_str(&tmp);
359
      if (cs->mbmaxlen > 1 &&
1578.2.16 by Brian Aker
Merge in change to getTable() to private the field objects.
360
          table->getField(key_part->fieldnr - 1)->field_length !=
1 by brian
clean slate
361
          key_part->length)
362
      {
363
        /*
364
          Prefix key, multi-byte charset.
365
          For the columns of type CHAR(N), the above val_str()
366
          call will return exactly "key_part->length" bytes,
367
          which can break a multi-byte characters in the middle.
368
          Align, returning not more than "char_length" characters.
369
        */
482 by Brian Aker
Remove uint.
370
        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.
371
        if ((charpos= my_charpos(cs, tmp.c_ptr(),
372
                                 tmp.c_ptr() + tmp.length(),
1 by brian
clean slate
373
                                 char_length)) < key_part->length)
374
          tmp.length(charpos);
375
      }
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
376
1 by brian
clean slate
377
      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).
378
        tmp.length(min(tmp.length(), static_cast<size_t>(key_part->length)));
1 by brian
clean slate
379
      to->append(tmp);
380
    }
381
    else
382
      to->append(STRING_WITH_LEN("???"));
383
  }
384
}
385
386
387
/*
388
  Check if key uses field that is marked in passed field bitmap.
389
390
  SYNOPSIS
391
    is_key_used()
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
392
      table   Table object with which keys and fields are associated.
1 by brian
clean slate
393
      idx     Key to be checked.
394
      fields  Bitmap of fields to be checked.
395
396
  NOTE
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
397
    This function uses Table::tmp_set bitmap so the caller should care
1 by brian
clean slate
398
    about saving/restoring its state if it also uses this bitmap.
399
400
  RETURN VALUE
401
    TRUE   Key uses field from bitmap
402
    FALSE  Otherwise
403
*/
404
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.
405
bool is_key_used(Table *table, uint32_t idx, const boost::dynamic_bitset<>& fields)
406
{
1802.16.8 by Padraig O'Sullivan
Removal of all MyBitmap from the code base. Compiles but test failures exist now.
407
  table->tmp_set.reset();
408
  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.
409
  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.
410
    return 1;
411
412
  /*
413
    If table handler has primary key as part of the index, check that primary
414
    key is not updated
415
  */
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
  }
421
  return 0;
422
}
423
424
1 by brian
clean slate
425
/**
426
  Compare key in row to a given key.
427
428
  @param key_part		Key part handler
1672.3.6 by Brian Aker
First pass in encapsulating row
429
  @param key			Key to compare to value in table->getInsertRecord()
1 by brian
clean slate
430
  @param key_length		length of 'key'
431
432
  @return
433
    The return value is SIGN(key_in_row - range_key):
434
    -   0		Key is equal to range or 'range' == 0 (no range)
435
    -  -1		Key is less than range
436
    -   1		Key is larger than range
437
*/
438
1534 by Brian Aker
Remove of KeyPartInfo
439
int key_cmp(KeyPartInfo *key_part, const unsigned char *key, uint32_t key_length)
1 by brian
clean slate
440
{
482 by Brian Aker
Remove uint.
441
  uint32_t store_length;
1 by brian
clean slate
442
481 by Brian Aker
Remove all of uchar.
443
  for (const unsigned char *end=key + key_length;
1 by brian
clean slate
444
       key < end;
445
       key+= store_length, key_part++)
446
  {
447
    int cmp;
448
    store_length= key_part->store_length;
449
    if (key_part->null_bit)
450
    {
451
      /* This key part allows null values; NULL is lower than everything */
452
      register bool field_is_null= key_part->field->is_null();
453
      if (*key)                                 // If range key is null
454
      {
455
	/* the range is expecting a null value */
456
	if (!field_is_null)
457
	  return 1;                             // Found key is > range
458
        /* null -- exact match, go to next key part */
459
	continue;
460
      }
461
      else if (field_is_null)
462
	return -1;                              // NULL is less than any value
463
      key++;					// Skip null byte
464
      store_length--;
465
    }
466
    if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0)
467
      return -1;
468
    if (cmp > 0)
469
      return 1;
470
  }
471
  return 0;                                     // Keys are equal
472
}
473
474
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
475
} /* namespace drizzled */