~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
243.1.17 by Jay Pipes
FINAL PHASE removal of mysql_priv.h (Bye, bye my friend.)
19
#include <drizzled/server_includes.h>
1 by brian
clean slate
20
21
/*
22
  Search after a key that starts with 'field'
23
24
  SYNOPSIS
25
    find_ref_key()
26
    key			First key to check
27
    key_count		How many keys to check
28
    record		Start of record
29
    field		Field to search after
30
    key_length		On partial match, contains length of fields before
31
			field
32
    keypart             key part # of a field
33
34
  NOTES
35
   Used when calculating key for NEXT_NUMBER
36
37
  IMPLEMENTATION
38
    If no key starts with field test if field is part of some key. If we find
39
    one, then return first key and set key_length to the number of bytes
40
    preceding 'field'.
41
42
  RETURN
43
   -1  field is not part of the key
44
   #   Key part for key matching key.
45
       key_length is set to length of key before (not including) field
46
*/
47
482 by Brian Aker
Remove uint.
48
int find_ref_key(KEY *key, uint32_t key_count, unsigned char *record, Field *field,
49
                 uint32_t *key_length, uint32_t *keypart)
1 by brian
clean slate
50
{
51
  register int i;
52
  register KEY *key_info;
482 by Brian Aker
Remove uint.
53
  uint32_t fieldpos;
1 by brian
clean slate
54
55
  fieldpos= field->offset(record);
56
57
  /* Test if some key starts as fieldpos */
58
  for (i= 0, key_info= key ;
59
       i < (int) key_count ;
60
       i++, key_info++)
61
  {
62
    if (key_info->key_part[0].offset == fieldpos)
63
    {                                  		/* Found key. Calc keylength */
64
      *key_length= *keypart= 0;
65
      return i;                                 /* Use this key */
66
    }
67
  }
68
69
  /* Test if some key contains fieldpos */
70
  for (i= 0, key_info= key;
71
       i < (int) key_count ;
72
       i++, key_info++)
73
  {
482 by Brian Aker
Remove uint.
74
    uint32_t j;
1 by brian
clean slate
75
    KEY_PART_INFO *key_part;
76
    *key_length=0;
77
    for (j=0, key_part=key_info->key_part ;
78
	 j < key_info->key_parts ;
79
	 j++, key_part++)
80
    {
81
      if (key_part->offset == fieldpos)
82
      {
83
        *keypart= j;
84
        return i;                               /* Use this key */
85
      }
86
      *key_length+= key_part->store_length;
87
    }
88
  }
89
  return(-1);					/* No key is ok */
90
}
91
92
93
/**
94
  Copy part of a record that forms a key or key prefix to a buffer.
95
96
    The function takes a complete table record (as e.g. retrieved by
97
    handler::index_read()), and a description of an index on the same table,
98
    and extracts the first key_length bytes of the record which are part of a
99
    key into to_key. If length == 0 then copy all bytes from the record that
100
    form a key.
101
102
  @param to_key      buffer that will be used as a key
103
  @param from_record full record to be copied from
104
  @param key_info    descriptor of the index
105
  @param key_length  specifies length of all keyparts that will be copied
106
*/
107
481 by Brian Aker
Remove all of uchar.
108
void key_copy(unsigned char *to_key, unsigned char *from_record, KEY *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;
1 by brian
clean slate
112
  KEY_PART_INFO *key_part;
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;
398.1.4 by Monty Taylor
Renamed max/min.
128
      length= cmin((uint16_t)key_length, key_part->length);
1 by brian
clean slate
129
      key_part->field->get_key_image(to_key, length, Field::itRAW);
130
      to_key+= HA_KEY_BLOB_LENGTH;
131
    }
132
    else
133
    {
398.1.4 by Monty Taylor
Renamed max/min.
134
      length= cmin((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();
482 by Brian Aker
Remove uint.
137
      uint32_t bytes= field->get_key_image(to_key, length, Field::itRAW);
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
481 by Brian Aker
Remove all of uchar.
151
void key_zero_nulls(unsigned char *tuple, KEY *key_info)
1 by brian
clean slate
152
{
153
  KEY_PART_INFO *key_part= key_info->key_part;
154
  KEY_PART_INFO *key_part_end= key_part + key_info->key_parts;
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
481 by Brian Aker
Remove all of uchar.
176
void key_restore(unsigned char *to_record, unsigned char *from_key, KEY *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;
1 by brian
clean slate
180
  KEY_PART_INFO *key_part;
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.
205
      */
482 by Brian Aker
Remove uint.
206
      uint32_t blob_length= uint2korr(from_key);
1 by brian
clean slate
207
      Field_blob *field= (Field_blob*) key_part->field;
208
      from_key+= HA_KEY_BLOB_LENGTH;
209
      key_length-= HA_KEY_BLOB_LENGTH;
210
      field->set_ptr_offset(to_record - field->table->record[0],
211
                            (ulong) blob_length, from_key);
212
      length= key_part->length;
213
    }
214
    else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
215
    {
216
      Field *field= key_part->field;
217
      my_ptrdiff_t ptrdiff= to_record - field->table->record[0];
218
      field->move_field_offset(ptrdiff);
219
      key_length-= HA_KEY_BLOB_LENGTH;
398.1.4 by Monty Taylor
Renamed max/min.
220
      length= cmin(key_length, key_part->length);
1 by brian
clean slate
221
      field->set_key_image(from_key, length);
222
      from_key+= HA_KEY_BLOB_LENGTH;
223
      field->move_field_offset(-ptrdiff);
224
    }
225
    else
226
    {
398.1.4 by Monty Taylor
Renamed max/min.
227
      length= cmin(key_length, key_part->length);
1 by brian
clean slate
228
      /* skip the byte with 'uneven' bits, if used */
229
      memcpy(to_record + key_part->offset, from_key + used_uneven_bits
230
             , (size_t) length - used_uneven_bits);
231
    }
232
    from_key+= length;
233
    key_length-= length;
234
  }
235
}
236
237
238
/**
239
  Compare if a key has changed.
240
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
241
  @param table		Table
1 by brian
clean slate
242
  @param key		key to compare to row
243
  @param idx		Index used
244
  @param key_length	Length of key
245
246
  @note
247
    In theory we could just call field->cmp() for all field types,
248
    but as we are only interested if a key has changed (not if the key is
249
    larger or smaller than the previous value) we can do things a bit
250
    faster by using memcmp() instead.
251
252
  @retval
253
    0	If key is equal
254
  @retval
255
    1	Key has changed
256
*/
257
482 by Brian Aker
Remove uint.
258
bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
1 by brian
clean slate
259
{
482 by Brian Aker
Remove uint.
260
  uint32_t store_length;
1 by brian
clean slate
261
  KEY_PART_INFO *key_part;
481 by Brian Aker
Remove all of uchar.
262
  const unsigned char *key_end= key + key_length;;
1 by brian
clean slate
263
264
  for (key_part=table->key_info[idx].key_part;
265
       key < key_end ; 
266
       key_part++, key+= store_length)
267
  {
482 by Brian Aker
Remove uint.
268
    uint32_t length;
1 by brian
clean slate
269
    store_length= key_part->store_length;
270
271
    if (key_part->null_bit)
272
    {
273
      if (*key != test(table->record[0][key_part->null_offset] & 
274
		       key_part->null_bit))
275
	return 1;
276
      if (*key)
277
	continue;
278
      key++;
279
      store_length--;
280
    }
281
    if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART |
282
                                   HA_BIT_PART))
283
    {
284
      if (key_part->field->key_cmp(key, key_part->length))
285
	return 1;
286
      continue;
287
    }
398.1.4 by Monty Taylor
Renamed max/min.
288
    length= cmin((uint) (key_end-key), store_length);
1 by brian
clean slate
289
    if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
290
                                FIELDFLAG_PACK)))
291
    {
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
292
      const CHARSET_INFO * const cs= key_part->field->charset();
482 by Brian Aker
Remove uint.
293
      uint32_t char_length= key_part->length / cs->mbmaxlen;
481 by Brian Aker
Remove all of uchar.
294
      const unsigned char *pos= table->record[0] + key_part->offset;
1 by brian
clean slate
295
      if (length > char_length)
296
      {
297
        char_length= my_charpos(cs, pos, pos + length, char_length);
298
        set_if_smaller(char_length, length);
299
      }
300
      if (cs->coll->strnncollsp(cs,
481 by Brian Aker
Remove all of uchar.
301
                                (const unsigned char*) key, length,
302
                                (const unsigned char*) pos, char_length, 0))
1 by brian
clean slate
303
        return 1;
304
      continue;
305
    }
306
    if (memcmp(key,table->record[0]+key_part->offset,length))
307
      return 1;
308
  }
309
  return 0;
310
}
311
312
/*
313
  unpack key-fields from record to some buffer.
314
315
  This is used mainly to get a good error message.  We temporary 
316
  change the column bitmap so that all columns are readable.
317
318
  @param
319
     to		Store value here in an easy to read form
320
  @param
321
     table	Table to use
322
  @param
323
     idx	Key number
324
*/
325
482 by Brian Aker
Remove uint.
326
void key_unpack(String *to,Table *table,uint32_t idx)
1 by brian
clean slate
327
{
328
  KEY_PART_INFO *key_part,*key_part_end;
329
  Field *field;
330
  String tmp;
331
332
  to->length(0);
333
  for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
334
	 table->key_info[idx].key_parts ;
335
       key_part < key_part_end;
336
       key_part++)
337
  {
338
    if (to->length())
339
      to->append('-');
340
    if (key_part->null_bit)
341
    {
342
      if (table->record[0][key_part->null_offset] & key_part->null_bit)
343
      {
344
	to->append(STRING_WITH_LEN("NULL"));
345
	continue;
346
      }
347
    }
348
    if ((field=key_part->field))
349
    {
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
350
      const CHARSET_INFO * const cs= field->charset();
1 by brian
clean slate
351
      field->val_str(&tmp);
352
      if (cs->mbmaxlen > 1 &&
353
          table->field[key_part->fieldnr - 1]->field_length !=
354
          key_part->length)
355
      {
356
        /*
357
          Prefix key, multi-byte charset.
358
          For the columns of type CHAR(N), the above val_str()
359
          call will return exactly "key_part->length" bytes,
360
          which can break a multi-byte characters in the middle.
361
          Align, returning not more than "char_length" characters.
362
        */
482 by Brian Aker
Remove uint.
363
        uint32_t charpos, char_length= key_part->length / cs->mbmaxlen;
1 by brian
clean slate
364
        if ((charpos= my_charpos(cs, tmp.ptr(),
365
                                 tmp.ptr() + tmp.length(),
366
                                 char_length)) < key_part->length)
367
          tmp.length(charpos);
368
      }
369
      
370
      if (key_part->length < field->pack_length())
398.1.4 by Monty Taylor
Renamed max/min.
371
	tmp.length(cmin(tmp.length(),(uint32_t)key_part->length));
1 by brian
clean slate
372
      to->append(tmp);
373
    }
374
    else
375
      to->append(STRING_WITH_LEN("???"));
376
  }
327.2.3 by Brian Aker
Refactoring of class Table
377
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
378
  return;
1 by brian
clean slate
379
}
380
381
382
/*
383
  Check if key uses field that is marked in passed field bitmap.
384
385
  SYNOPSIS
386
    is_key_used()
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
387
      table   Table object with which keys and fields are associated.
1 by brian
clean slate
388
      idx     Key to be checked.
389
      fields  Bitmap of fields to be checked.
390
391
  NOTE
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
392
    This function uses Table::tmp_set bitmap so the caller should care
1 by brian
clean slate
393
    about saving/restoring its state if it also uses this bitmap.
394
395
  RETURN VALUE
396
    TRUE   Key uses field from bitmap
397
    FALSE  Otherwise
398
*/
399
482 by Brian Aker
Remove uint.
400
bool is_key_used(Table *table, uint32_t idx, const MY_BITMAP *fields)
1 by brian
clean slate
401
{
402
  bitmap_clear_all(&table->tmp_set);
403
  table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
404
  if (bitmap_is_overlapping(&table->tmp_set, fields))
405
    return 1;
406
407
  /*
408
    If table handler has primary key as part of the index, check that primary
409
    key is not updated
410
  */
411
  if (idx != table->s->primary_key && table->s->primary_key < MAX_KEY &&
412
      (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
413
    return is_key_used(table, table->s->primary_key, fields);
414
  return 0;
415
}
416
417
418
/**
419
  Compare key in row to a given key.
420
421
  @param key_part		Key part handler
422
  @param key			Key to compare to value in table->record[0]
423
  @param key_length		length of 'key'
424
425
  @return
426
    The return value is SIGN(key_in_row - range_key):
427
    -   0		Key is equal to range or 'range' == 0 (no range)
428
    -  -1		Key is less than range
429
    -   1		Key is larger than range
430
*/
431
482 by Brian Aker
Remove uint.
432
int key_cmp(KEY_PART_INFO *key_part, const unsigned char *key, uint32_t key_length)
1 by brian
clean slate
433
{
482 by Brian Aker
Remove uint.
434
  uint32_t store_length;
1 by brian
clean slate
435
481 by Brian Aker
Remove all of uchar.
436
  for (const unsigned char *end=key + key_length;
1 by brian
clean slate
437
       key < end;
438
       key+= store_length, key_part++)
439
  {
440
    int cmp;
441
    store_length= key_part->store_length;
442
    if (key_part->null_bit)
443
    {
444
      /* This key part allows null values; NULL is lower than everything */
445
      register bool field_is_null= key_part->field->is_null();
446
      if (*key)                                 // If range key is null
447
      {
448
	/* the range is expecting a null value */
449
	if (!field_is_null)
450
	  return 1;                             // Found key is > range
451
        /* null -- exact match, go to next key part */
452
	continue;
453
      }
454
      else if (field_is_null)
455
	return -1;                              // NULL is less than any value
456
      key++;					// Skip null byte
457
      store_length--;
458
    }
459
    if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0)
460
      return -1;
461
    if (cmp > 0)
462
      return 1;
463
  }
464
  return 0;                                     // Keys are equal
465
}
466
467
468
/*
469
  Compare two records in index order
470
  SYNOPSIS
471
    key_rec_cmp()
472
    key                         Index information
473
    rec0                        Pointer to table->record[0]
474
    first_rec                   Pointer to record compare with
475
    second_rec                  Pointer to record compare against first_rec
476
477
  DESCRIPTION
478
    This method is set-up such that it can be called directly from the
479
    priority queue and it is attempted to be optimised as much as possible
480
    since this will be called O(N * log N) times while performing a merge
481
    sort in various places in the code.
482
483
    We retrieve the pointer to table->record[0] using the fact that key_parts
484
    have an offset making it possible to calculate the start of the record.
485
    We need to get the diff to the compared record since none of the records
486
    being compared are stored in table->record[0].
487
488
    We first check for NULL values, if there are no NULL values we use
489
    a compare method that gets two field pointers and a max length
490
    and return the result of the comparison.
491
*/
492
481 by Brian Aker
Remove all of uchar.
493
int key_rec_cmp(void *key, unsigned char *first_rec, unsigned char *second_rec)
1 by brian
clean slate
494
{
495
  KEY *key_info= (KEY*)key;
482 by Brian Aker
Remove uint.
496
  uint32_t key_parts= key_info->key_parts, i= 0;
1 by brian
clean slate
497
  KEY_PART_INFO *key_part= key_info->key_part;
481 by Brian Aker
Remove all of uchar.
498
  unsigned char *rec0= key_part->field->ptr - key_part->offset;
1 by brian
clean slate
499
  my_ptrdiff_t first_diff= first_rec - rec0, sec_diff= second_rec - rec0;
500
  int result= 0;
501
502
  do
503
  {
504
    Field *field= key_part->field;
505
506
    if (key_part->null_bit)
507
    {
508
      /* The key_part can contain NULL values */
509
      bool first_is_null= field->is_null_in_record_with_offset(first_diff);
510
      bool sec_is_null= field->is_null_in_record_with_offset(sec_diff);
511
      /*
512
        NULL is smaller then everything so if first is NULL and the other
513
        not then we know that we should return -1 and for the opposite
514
        we should return +1. If both are NULL then we call it equality
515
        although it is a strange form of equality, we have equally little
516
        information of the real value.
517
      */
518
      if (!first_is_null)
519
      {
520
        if (!sec_is_null)
521
          ; /* Fall through, no NULL fields */
522
        else
523
        {
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
524
          return(1);
1 by brian
clean slate
525
        }
526
      }
527
      else if (!sec_is_null)
528
      {
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
529
        return(-1);
1 by brian
clean slate
530
      }
531
      else
532
        goto next_loop; /* Both were NULL */
533
    }
534
    /*
535
      No null values in the fields
536
      We use the virtual method cmp_max with a max length parameter.
537
      For most field types this translates into a cmp without
538
      max length. The exceptions are the BLOB and VARCHAR field types
539
      that take the max length into account.
540
    */
541
    result= field->cmp_max(field->ptr+first_diff, field->ptr+sec_diff,
542
                           key_part->length);
543
next_loop:
544
    key_part++;
545
  } while (!result && ++i < key_parts);
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
546
  return(result);
1 by brian
clean slate
547
}