~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
19
#include "mysql_priv.h"
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
48
int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field,
49
                 uint *key_length, uint *keypart)
50
{
51
  register int i;
52
  register KEY *key_info;
53
  uint fieldpos;
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
  {
74
    uint j;
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
108
void key_copy(uchar *to_key, uchar *from_record, KEY *key_info,
109
              uint key_length)
110
{
111
  uint length;
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;
128
      length= min(key_length, key_part->length);
129
      key_part->field->get_key_image(to_key, length, Field::itRAW);
130
      to_key+= HA_KEY_BLOB_LENGTH;
131
    }
132
    else
133
    {
134
      length= min(key_length, key_part->length);
135
      Field *field= key_part->field;
136
      CHARSET_INFO *cs= field->charset();
137
      uint bytes= field->get_key_image(to_key, length, Field::itRAW);
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
151
void key_zero_nulls(uchar *tuple, KEY *key_info)
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)
158
      bzero(tuple+1, key_part->store_length-1);
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
176
void key_restore(uchar *to_record, uchar *from_key, KEY *key_info,
177
                 uint key_length)
178
{
179
  uint length;
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
  {
188
    uchar used_uneven_bits= 0;
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
      */
206
      uint blob_length= uint2korr(from_key);
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_bitmap_map *old_map;
218
      my_ptrdiff_t ptrdiff= to_record - field->table->record[0];
219
      field->move_field_offset(ptrdiff);
220
      key_length-= HA_KEY_BLOB_LENGTH;
221
      length= min(key_length, key_part->length);
222
      old_map= dbug_tmp_use_all_columns(field->table, field->table->write_set);
223
      field->set_key_image(from_key, length);
224
      dbug_tmp_restore_column_map(field->table->write_set, old_map);
225
      from_key+= HA_KEY_BLOB_LENGTH;
226
      field->move_field_offset(-ptrdiff);
227
    }
228
    else
229
    {
230
      length= min(key_length, key_part->length);
231
      /* skip the byte with 'uneven' bits, if used */
232
      memcpy(to_record + key_part->offset, from_key + used_uneven_bits
233
             , (size_t) length - used_uneven_bits);
234
    }
235
    from_key+= length;
236
    key_length-= length;
237
  }
238
}
239
240
241
/**
242
  Compare if a key has changed.
243
244
  @param table		TABLE
245
  @param key		key to compare to row
246
  @param idx		Index used
247
  @param key_length	Length of key
248
249
  @note
250
    In theory we could just call field->cmp() for all field types,
251
    but as we are only interested if a key has changed (not if the key is
252
    larger or smaller than the previous value) we can do things a bit
253
    faster by using memcmp() instead.
254
255
  @retval
256
    0	If key is equal
257
  @retval
258
    1	Key has changed
259
*/
260
261
bool key_cmp_if_same(TABLE *table,const uchar *key,uint idx,uint key_length)
262
{
263
  uint store_length;
264
  KEY_PART_INFO *key_part;
265
  const uchar *key_end= key + key_length;;
266
267
  for (key_part=table->key_info[idx].key_part;
268
       key < key_end ; 
269
       key_part++, key+= store_length)
270
  {
271
    uint length;
272
    store_length= key_part->store_length;
273
274
    if (key_part->null_bit)
275
    {
276
      if (*key != test(table->record[0][key_part->null_offset] & 
277
		       key_part->null_bit))
278
	return 1;
279
      if (*key)
280
	continue;
281
      key++;
282
      store_length--;
283
    }
284
    if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART |
285
                                   HA_BIT_PART))
286
    {
287
      if (key_part->field->key_cmp(key, key_part->length))
288
	return 1;
289
      continue;
290
    }
291
    length= min((uint) (key_end-key), store_length);
292
    if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
293
                                FIELDFLAG_PACK)))
294
    {
295
      CHARSET_INFO *cs= key_part->field->charset();
296
      uint char_length= key_part->length / cs->mbmaxlen;
297
      const uchar *pos= table->record[0] + key_part->offset;
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,
304
                                (const uchar*) key, length,
305
                                (const uchar*) pos, char_length, 0))
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
318
  This is used mainly to get a good error message.  We temporary 
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
329
void key_unpack(String *to,TABLE *table,uint idx)
330
{
331
  KEY_PART_INFO *key_part,*key_part_end;
332
  Field *field;
333
  String tmp;
334
  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
335
336
  to->length(0);
337
  for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
338
	 table->key_info[idx].key_parts ;
339
       key_part < key_part_end;
340
       key_part++)
341
  {
342
    if (to->length())
343
      to->append('-');
344
    if (key_part->null_bit)
345
    {
346
      if (table->record[0][key_part->null_offset] & key_part->null_bit)
347
      {
348
	to->append(STRING_WITH_LEN("NULL"));
349
	continue;
350
      }
351
    }
352
    if ((field=key_part->field))
353
    {
354
      CHARSET_INFO *cs= field->charset();
355
      field->val_str(&tmp);
356
      if (cs->mbmaxlen > 1 &&
357
          table->field[key_part->fieldnr - 1]->field_length !=
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
        */
367
        uint charpos, char_length= key_part->length / cs->mbmaxlen;
368
        if ((charpos= my_charpos(cs, tmp.ptr(),
369
                                 tmp.ptr() + tmp.length(),
370
                                 char_length)) < key_part->length)
371
          tmp.length(charpos);
372
      }
373
      
374
      if (key_part->length < field->pack_length())
375
	tmp.length(min(tmp.length(),key_part->length));
376
      to->append(tmp);
377
    }
378
    else
379
      to->append(STRING_WITH_LEN("???"));
380
  }
381
  dbug_tmp_restore_column_map(table->read_set, old_map);
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
382
  return;
1 by brian
clean slate
383
}
384
385
386
/*
387
  Check if key uses field that is marked in passed field bitmap.
388
389
  SYNOPSIS
390
    is_key_used()
391
      table   TABLE object with which keys and fields are associated.
392
      idx     Key to be checked.
393
      fields  Bitmap of fields to be checked.
394
395
  NOTE
396
    This function uses TABLE::tmp_set bitmap so the caller should care
397
    about saving/restoring its state if it also uses this bitmap.
398
399
  RETURN VALUE
400
    TRUE   Key uses field from bitmap
401
    FALSE  Otherwise
402
*/
403
404
bool is_key_used(TABLE *table, uint idx, const MY_BITMAP *fields)
405
{
406
  bitmap_clear_all(&table->tmp_set);
407
  table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
408
  if (bitmap_is_overlapping(&table->tmp_set, fields))
409
    return 1;
410
411
  /*
412
    If table handler has primary key as part of the index, check that primary
413
    key is not updated
414
  */
415
  if (idx != table->s->primary_key && table->s->primary_key < MAX_KEY &&
416
      (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
417
    return is_key_used(table, table->s->primary_key, fields);
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
436
int key_cmp(KEY_PART_INFO *key_part, const uchar *key, uint key_length)
437
{
438
  uint store_length;
439
440
  for (const uchar *end=key + key_length;
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
472
/*
473
  Compare two records in index order
474
  SYNOPSIS
475
    key_rec_cmp()
476
    key                         Index information
477
    rec0                        Pointer to table->record[0]
478
    first_rec                   Pointer to record compare with
479
    second_rec                  Pointer to record compare against first_rec
480
481
  DESCRIPTION
482
    This method is set-up such that it can be called directly from the
483
    priority queue and it is attempted to be optimised as much as possible
484
    since this will be called O(N * log N) times while performing a merge
485
    sort in various places in the code.
486
487
    We retrieve the pointer to table->record[0] using the fact that key_parts
488
    have an offset making it possible to calculate the start of the record.
489
    We need to get the diff to the compared record since none of the records
490
    being compared are stored in table->record[0].
491
492
    We first check for NULL values, if there are no NULL values we use
493
    a compare method that gets two field pointers and a max length
494
    and return the result of the comparison.
495
*/
496
497
int key_rec_cmp(void *key, uchar *first_rec, uchar *second_rec)
498
{
499
  KEY *key_info= (KEY*)key;
500
  uint key_parts= key_info->key_parts, i= 0;
501
  KEY_PART_INFO *key_part= key_info->key_part;
502
  uchar *rec0= key_part->field->ptr - key_part->offset;
503
  my_ptrdiff_t first_diff= first_rec - rec0, sec_diff= second_rec - rec0;
504
  int result= 0;
505
506
  do
507
  {
508
    Field *field= key_part->field;
509
510
    if (key_part->null_bit)
511
    {
512
      /* The key_part can contain NULL values */
513
      bool first_is_null= field->is_null_in_record_with_offset(first_diff);
514
      bool sec_is_null= field->is_null_in_record_with_offset(sec_diff);
515
      /*
516
        NULL is smaller then everything so if first is NULL and the other
517
        not then we know that we should return -1 and for the opposite
518
        we should return +1. If both are NULL then we call it equality
519
        although it is a strange form of equality, we have equally little
520
        information of the real value.
521
      */
522
      if (!first_is_null)
523
      {
524
        if (!sec_is_null)
525
          ; /* Fall through, no NULL fields */
526
        else
527
        {
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
528
          return(1);
1 by brian
clean slate
529
        }
530
      }
531
      else if (!sec_is_null)
532
      {
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
533
        return(-1);
1 by brian
clean slate
534
      }
535
      else
536
        goto next_loop; /* Both were NULL */
537
    }
538
    /*
539
      No null values in the fields
540
      We use the virtual method cmp_max with a max length parameter.
541
      For most field types this translates into a cmp without
542
      max length. The exceptions are the BLOB and VARCHAR field types
543
      that take the max length into account.
544
    */
545
    result= field->cmp_max(field->ptr+first_diff, field->ptr+sec_diff,
546
                           key_part->length);
547
next_loop:
548
    key_part++;
549
  } while (!result && ++i < key_parts);
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
550
  return(result);
1 by brian
clean slate
551
}