~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
  DBUG_ENTER("key_unpack");
336
337
  to->length(0);
338
  for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
339
	 table->key_info[idx].key_parts ;
340
       key_part < key_part_end;
341
       key_part++)
342
  {
343
    if (to->length())
344
      to->append('-');
345
    if (key_part->null_bit)
346
    {
347
      if (table->record[0][key_part->null_offset] & key_part->null_bit)
348
      {
349
	to->append(STRING_WITH_LEN("NULL"));
350
	continue;
351
      }
352
    }
353
    if ((field=key_part->field))
354
    {
355
      CHARSET_INFO *cs= field->charset();
356
      field->val_str(&tmp);
357
      if (cs->mbmaxlen > 1 &&
358
          table->field[key_part->fieldnr - 1]->field_length !=
359
          key_part->length)
360
      {
361
        /*
362
          Prefix key, multi-byte charset.
363
          For the columns of type CHAR(N), the above val_str()
364
          call will return exactly "key_part->length" bytes,
365
          which can break a multi-byte characters in the middle.
366
          Align, returning not more than "char_length" characters.
367
        */
368
        uint charpos, char_length= key_part->length / cs->mbmaxlen;
369
        if ((charpos= my_charpos(cs, tmp.ptr(),
370
                                 tmp.ptr() + tmp.length(),
371
                                 char_length)) < key_part->length)
372
          tmp.length(charpos);
373
      }
374
      
375
      if (key_part->length < field->pack_length())
376
	tmp.length(min(tmp.length(),key_part->length));
377
      to->append(tmp);
378
    }
379
    else
380
      to->append(STRING_WITH_LEN("???"));
381
  }
382
  dbug_tmp_restore_column_map(table->read_set, old_map);
383
  DBUG_VOID_RETURN;
384
}
385
386
387
/*
388
  Check if key uses field that is marked in passed field bitmap.
389
390
  SYNOPSIS
391
    is_key_used()
392
      table   TABLE object with which keys and fields are associated.
393
      idx     Key to be checked.
394
      fields  Bitmap of fields to be checked.
395
396
  NOTE
397
    This function uses TABLE::tmp_set bitmap so the caller should care
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
405
bool is_key_used(TABLE *table, uint idx, const MY_BITMAP *fields)
406
{
407
  bitmap_clear_all(&table->tmp_set);
408
  table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
409
  if (bitmap_is_overlapping(&table->tmp_set, fields))
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->s->primary_key && table->s->primary_key < MAX_KEY &&
417
      (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
418
    return is_key_used(table, table->s->primary_key, fields);
419
  return 0;
420
}
421
422
423
/**
424
  Compare key in row to a given key.
425
426
  @param key_part		Key part handler
427
  @param key			Key to compare to value in table->record[0]
428
  @param key_length		length of 'key'
429
430
  @return
431
    The return value is SIGN(key_in_row - range_key):
432
    -   0		Key is equal to range or 'range' == 0 (no range)
433
    -  -1		Key is less than range
434
    -   1		Key is larger than range
435
*/
436
437
int key_cmp(KEY_PART_INFO *key_part, const uchar *key, uint key_length)
438
{
439
  uint store_length;
440
441
  for (const uchar *end=key + key_length;
442
       key < end;
443
       key+= store_length, key_part++)
444
  {
445
    int cmp;
446
    store_length= key_part->store_length;
447
    if (key_part->null_bit)
448
    {
449
      /* This key part allows null values; NULL is lower than everything */
450
      register bool field_is_null= key_part->field->is_null();
451
      if (*key)                                 // If range key is null
452
      {
453
	/* the range is expecting a null value */
454
	if (!field_is_null)
455
	  return 1;                             // Found key is > range
456
        /* null -- exact match, go to next key part */
457
	continue;
458
      }
459
      else if (field_is_null)
460
	return -1;                              // NULL is less than any value
461
      key++;					// Skip null byte
462
      store_length--;
463
    }
464
    if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0)
465
      return -1;
466
    if (cmp > 0)
467
      return 1;
468
  }
469
  return 0;                                     // Keys are equal
470
}
471
472
473
/*
474
  Compare two records in index order
475
  SYNOPSIS
476
    key_rec_cmp()
477
    key                         Index information
478
    rec0                        Pointer to table->record[0]
479
    first_rec                   Pointer to record compare with
480
    second_rec                  Pointer to record compare against first_rec
481
482
  DESCRIPTION
483
    This method is set-up such that it can be called directly from the
484
    priority queue and it is attempted to be optimised as much as possible
485
    since this will be called O(N * log N) times while performing a merge
486
    sort in various places in the code.
487
488
    We retrieve the pointer to table->record[0] using the fact that key_parts
489
    have an offset making it possible to calculate the start of the record.
490
    We need to get the diff to the compared record since none of the records
491
    being compared are stored in table->record[0].
492
493
    We first check for NULL values, if there are no NULL values we use
494
    a compare method that gets two field pointers and a max length
495
    and return the result of the comparison.
496
*/
497
498
int key_rec_cmp(void *key, uchar *first_rec, uchar *second_rec)
499
{
500
  KEY *key_info= (KEY*)key;
501
  uint key_parts= key_info->key_parts, i= 0;
502
  KEY_PART_INFO *key_part= key_info->key_part;
503
  uchar *rec0= key_part->field->ptr - key_part->offset;
504
  my_ptrdiff_t first_diff= first_rec - rec0, sec_diff= second_rec - rec0;
505
  int result= 0;
506
  DBUG_ENTER("key_rec_cmp");
507
508
  do
509
  {
510
    Field *field= key_part->field;
511
512
    if (key_part->null_bit)
513
    {
514
      /* The key_part can contain NULL values */
515
      bool first_is_null= field->is_null_in_record_with_offset(first_diff);
516
      bool sec_is_null= field->is_null_in_record_with_offset(sec_diff);
517
      /*
518
        NULL is smaller then everything so if first is NULL and the other
519
        not then we know that we should return -1 and for the opposite
520
        we should return +1. If both are NULL then we call it equality
521
        although it is a strange form of equality, we have equally little
522
        information of the real value.
523
      */
524
      if (!first_is_null)
525
      {
526
        if (!sec_is_null)
527
          ; /* Fall through, no NULL fields */
528
        else
529
        {
530
          DBUG_RETURN(+1);
531
        }
532
      }
533
      else if (!sec_is_null)
534
      {
535
        DBUG_RETURN(-1);
536
      }
537
      else
538
        goto next_loop; /* Both were NULL */
539
    }
540
    /*
541
      No null values in the fields
542
      We use the virtual method cmp_max with a max length parameter.
543
      For most field types this translates into a cmp without
544
      max length. The exceptions are the BLOB and VARCHAR field types
545
      that take the max length into account.
546
    */
547
    result= field->cmp_max(field->ptr+first_diff, field->ptr+sec_diff,
548
                           key_part->length);
549
next_loop:
550
    key_part++;
551
  } while (!result && ++i < key_parts);
552
  DBUG_RETURN(result);
553
}