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