~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
934.2.21 by Jay Pipes
Move Key stuff into key.cc and out of session.cc
19
#include "drizzled/server_includes.h"
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
1 by brian
clean slate
30
/*
31
  Search after a key that starts with 'field'
32
33
  SYNOPSIS
34
    find_ref_key()
35
    key			First key to check
36
    key_count		How many keys to check
37
    record		Start of record
38
    field		Field to search after
39
    key_length		On partial match, contains length of fields before
40
			field
41
    keypart             key part # of a field
42
43
  NOTES
44
   Used when calculating key for NEXT_NUMBER
45
46
  IMPLEMENTATION
47
    If no key starts with field test if field is part of some key. If we find
48
    one, then return first key and set key_length to the number of bytes
49
    preceding 'field'.
50
51
  RETURN
52
   -1  field is not part of the key
53
   #   Key part for key matching key.
54
       key_length is set to length of key before (not including) field
55
*/
56
482 by Brian Aker
Remove uint.
57
int find_ref_key(KEY *key, uint32_t key_count, unsigned char *record, Field *field,
58
                 uint32_t *key_length, uint32_t *keypart)
1 by brian
clean slate
59
{
60
  register int i;
61
  register KEY *key_info;
482 by Brian Aker
Remove uint.
62
  uint32_t fieldpos;
1 by brian
clean slate
63
64
  fieldpos= field->offset(record);
65
66
  /* Test if some key starts as fieldpos */
67
  for (i= 0, key_info= key ;
68
       i < (int) key_count ;
69
       i++, key_info++)
70
  {
71
    if (key_info->key_part[0].offset == fieldpos)
72
    {                                  		/* Found key. Calc keylength */
73
      *key_length= *keypart= 0;
74
      return i;                                 /* Use this key */
75
    }
76
  }
77
78
  /* Test if some key contains fieldpos */
79
  for (i= 0, key_info= key;
80
       i < (int) key_count ;
81
       i++, key_info++)
82
  {
482 by Brian Aker
Remove uint.
83
    uint32_t j;
1 by brian
clean slate
84
    KEY_PART_INFO *key_part;
85
    *key_length=0;
86
    for (j=0, key_part=key_info->key_part ;
87
	 j < key_info->key_parts ;
88
	 j++, key_part++)
89
    {
90
      if (key_part->offset == fieldpos)
91
      {
92
        *keypart= j;
93
        return i;                               /* Use this key */
94
      }
95
      *key_length+= key_part->store_length;
96
    }
97
  }
98
  return(-1);					/* No key is ok */
99
}
100
101
481 by Brian Aker
Remove all of uchar.
102
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
103
              unsigned int key_length)
1 by brian
clean slate
104
{
482 by Brian Aker
Remove uint.
105
  uint32_t length;
1 by brian
clean slate
106
  KEY_PART_INFO *key_part;
107
108
  if (key_length == 0)
109
    key_length= key_info->key_length;
110
  for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
111
  {
112
    if (key_part->null_bit)
113
    {
114
      *to_key++= test(from_record[key_part->null_offset] &
115
		   key_part->null_bit);
116
      key_length--;
117
    }
118
    if (key_part->key_part_flag & HA_BLOB_PART ||
119
        key_part->key_part_flag & HA_VAR_LENGTH_PART)
120
    {
121
      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).
122
      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...
123
      key_part->field->get_key_image(to_key, length);
1 by brian
clean slate
124
      to_key+= HA_KEY_BLOB_LENGTH;
125
    }
126
    else
127
    {
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);
1 by brian
clean slate
129
      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.
130
      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...
131
      uint32_t bytes= field->get_key_image(to_key, length);
1 by brian
clean slate
132
      if (bytes < length)
133
        cs->cset->fill(cs, (char*) to_key + bytes, length - bytes, ' ');
134
    }
135
    to_key+= length;
136
    key_length-= length;
137
  }
138
}
139
140
141
/**
142
  Zero the null components of key tuple.
143
*/
144
481 by Brian Aker
Remove all of uchar.
145
void key_zero_nulls(unsigned char *tuple, KEY *key_info)
1 by brian
clean slate
146
{
147
  KEY_PART_INFO *key_part= key_info->key_part;
148
  KEY_PART_INFO *key_part_end= key_part + key_info->key_parts;
149
  for (; key_part != key_part_end; key_part++)
150
  {
151
    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.
152
      memset(tuple+1, 0, key_part->store_length-1);
1 by brian
clean slate
153
    tuple+= key_part->store_length;
154
  }
155
}
156
157
158
/*
159
  Restore a key from some buffer to record.
160
161
    This function converts a key into record format. It can be used in cases
162
    when we want to return a key as a result row.
163
164
  @param to_record   record buffer where the key will be restored to
165
  @param from_key    buffer that contains a key
166
  @param key_info    descriptor of the index
167
  @param key_length  specifies length of all keyparts that will be restored
168
*/
169
481 by Brian Aker
Remove all of uchar.
170
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
171
                 uint16_t key_length)
1 by brian
clean slate
172
{
482 by Brian Aker
Remove uint.
173
  uint32_t length;
1 by brian
clean slate
174
  KEY_PART_INFO *key_part;
175
176
  if (key_length == 0)
177
  {
178
    key_length= key_info->key_length;
179
  }
180
  for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++)
181
  {
481 by Brian Aker
Remove all of uchar.
182
    unsigned char used_uneven_bits= 0;
1 by brian
clean slate
183
    if (key_part->null_bit)
184
    {
185
      if (*from_key++)
186
	to_record[key_part->null_offset]|= key_part->null_bit;
187
      else
188
	to_record[key_part->null_offset]&= ~key_part->null_bit;
189
      key_length--;
190
    }
191
    if (key_part->key_part_flag & HA_BLOB_PART)
192
    {
193
      /*
194
        This in fact never happens, as we have only partial BLOB
195
        keys yet anyway, so it's difficult to find any sence to
196
        restore the part of a record.
197
        Maybe this branch is to be removed, but now we
198
        have to ignore GCov compaining.
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
199
200
        This may make more sense once we push down block lengths to the engine (aka partial retrieval).
1 by brian
clean slate
201
      */
482 by Brian Aker
Remove uint.
202
      uint32_t blob_length= uint2korr(from_key);
1 by brian
clean slate
203
      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
204
205
      field->setReadSet();
1 by brian
clean slate
206
      from_key+= HA_KEY_BLOB_LENGTH;
207
      key_length-= HA_KEY_BLOB_LENGTH;
208
      field->set_ptr_offset(to_record - field->table->record[0],
209
                            (ulong) blob_length, from_key);
210
      length= key_part->length;
211
    }
212
    else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
213
    {
214
      Field *field= key_part->field;
215
      my_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
216
217
      field->setReadSet();
218
      field->setWriteSet();
1 by brian
clean slate
219
      field->move_field_offset(ptrdiff);
220
      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).
221
      length= min(key_length, key_part->length);
1 by brian
clean slate
222
      field->set_key_image(from_key, length);
223
      from_key+= HA_KEY_BLOB_LENGTH;
224
      field->move_field_offset(-ptrdiff);
225
    }
226
    else
227
    {
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).
228
      length= min(key_length, key_part->length);
1 by brian
clean slate
229
      /* skip the byte with 'uneven' bits, if used */
230
      memcpy(to_record + key_part->offset, from_key + used_uneven_bits
231
             , (size_t) length - used_uneven_bits);
232
    }
233
    from_key+= length;
234
    key_length-= length;
235
  }
236
}
237
238
239
/**
240
  Compare if a key has changed.
241
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
242
  @param table		Table
1 by brian
clean slate
243
  @param key		key to compare to row
244
  @param idx		Index used
245
  @param key_length	Length of key
246
247
  @note
248
    In theory we could just call field->cmp() for all field types,
249
    but as we are only interested if a key has changed (not if the key is
250
    larger or smaller than the previous value) we can do things a bit
251
    faster by using memcmp() instead.
252
253
  @retval
254
    0	If key is equal
255
  @retval
256
    1	Key has changed
257
*/
258
482 by Brian Aker
Remove uint.
259
bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
1 by brian
clean slate
260
{
482 by Brian Aker
Remove uint.
261
  uint32_t store_length;
1 by brian
clean slate
262
  KEY_PART_INFO *key_part;
481 by Brian Aker
Remove all of uchar.
263
  const unsigned char *key_end= key + key_length;;
1 by brian
clean slate
264
265
  for (key_part=table->key_info[idx].key_part;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
266
       key < key_end ;
1 by brian
clean slate
267
       key_part++, key+= store_length)
268
  {
482 by Brian Aker
Remove uint.
269
    uint32_t length;
1 by brian
clean slate
270
    store_length= key_part->store_length;
271
272
    if (key_part->null_bit)
273
    {
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
274
      if (*key != test(table->record[0][key_part->null_offset] &
1 by brian
clean slate
275
		       key_part->null_bit))
276
	return 1;
277
      if (*key)
278
	continue;
279
      key++;
280
      store_length--;
281
    }
282
    if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART |
283
                                   HA_BIT_PART))
284
    {
285
      if (key_part->field->key_cmp(key, key_part->length))
286
	return 1;
287
      continue;
288
    }
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).
289
    length= min((uint32_t) (key_end-key), store_length);
1 by brian
clean slate
290
    if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
291
                                FIELDFLAG_PACK)))
292
    {
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
293
      const CHARSET_INFO * const cs= key_part->field->charset();
482 by Brian Aker
Remove uint.
294
      uint32_t char_length= key_part->length / cs->mbmaxlen;
481 by Brian Aker
Remove all of uchar.
295
      const unsigned char *pos= table->record[0] + key_part->offset;
1 by brian
clean slate
296
      if (length > char_length)
297
      {
298
        char_length= my_charpos(cs, pos, pos + length, char_length);
299
        set_if_smaller(char_length, length);
300
      }
301
      if (cs->coll->strnncollsp(cs,
481 by Brian Aker
Remove all of uchar.
302
                                (const unsigned char*) key, length,
303
                                (const unsigned char*) pos, char_length, 0))
1 by brian
clean slate
304
        return 1;
305
      continue;
306
    }
307
    if (memcmp(key,table->record[0]+key_part->offset,length))
308
      return 1;
309
  }
310
  return 0;
311
}
312
313
/*
314
  unpack key-fields from record to some buffer.
315
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
316
  This is used mainly to get a good error message.  We temporary
1 by brian
clean slate
317
  change the column bitmap so that all columns are readable.
318
319
  @param
320
     to		Store value here in an easy to read form
321
  @param
322
     table	Table to use
323
  @param
324
     idx	Key number
325
*/
326
482 by Brian Aker
Remove uint.
327
void key_unpack(String *to,Table *table,uint32_t idx)
1 by brian
clean slate
328
{
329
  KEY_PART_INFO *key_part,*key_part_end;
330
  Field *field;
331
  String tmp;
332
333
  to->length(0);
334
  for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
335
	 table->key_info[idx].key_parts ;
336
       key_part < key_part_end;
337
       key_part++)
338
  {
339
    if (to->length())
340
      to->append('-');
341
    if (key_part->null_bit)
342
    {
343
      if (table->record[0][key_part->null_offset] & key_part->null_bit)
344
      {
345
	to->append(STRING_WITH_LEN("NULL"));
346
	continue;
347
      }
348
    }
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
349
    if ((field= key_part->field))
1 by brian
clean slate
350
    {
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
351
      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
352
      field->setReadSet();
1 by brian
clean slate
353
      field->val_str(&tmp);
354
      if (cs->mbmaxlen > 1 &&
355
          table->field[key_part->fieldnr - 1]->field_length !=
356
          key_part->length)
357
      {
358
        /*
359
          Prefix key, multi-byte charset.
360
          For the columns of type CHAR(N), the above val_str()
361
          call will return exactly "key_part->length" bytes,
362
          which can break a multi-byte characters in the middle.
363
          Align, returning not more than "char_length" characters.
364
        */
482 by Brian Aker
Remove uint.
365
        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.
366
        if ((charpos= my_charpos(cs, tmp.c_ptr(),
367
                                 tmp.c_ptr() + tmp.length(),
1 by brian
clean slate
368
                                 char_length)) < key_part->length)
369
          tmp.length(charpos);
370
      }
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
371
1 by brian
clean slate
372
      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).
373
        tmp.length(min(tmp.length(),(uint32_t)key_part->length));
1 by brian
clean slate
374
      to->append(tmp);
375
    }
376
    else
377
      to->append(STRING_WITH_LEN("???"));
378
  }
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
1005.2.3 by Monty Taylor
Further reversion of P.
400
bool is_key_used(Table *table, uint32_t idx, const MY_BITMAP *fields)
1 by brian
clean slate
401
{
1005.2.3 by Monty Taylor
Further reversion of P.
402
  bitmap_clear_all(&table->tmp_set);
1 by brian
clean slate
403
  table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
1005.2.3 by Monty Taylor
Further reversion of P.
404
  if (bitmap_is_overlapping(&table->tmp_set, fields))
1 by brian
clean slate
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
}
934.2.21 by Jay Pipes
Move Key stuff into key.cc and out of session.cc
548
549
Key::Key(const Key &rhs, MEM_ROOT *mem_root)
550
  :type(rhs.type),
551
  key_create_info(rhs.key_create_info),
552
  columns(rhs.columns, mem_root),
553
  name(rhs.name),
554
  generated(rhs.generated)
555
{
556
  list_copy_and_replace_each_value(columns, mem_root);
557
}