1/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
2 Copyright (c) 2018, MariaDB
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
17
18/* Functions to handle keys and fields in forms */
19
20#include "mariadb.h"
21#include "sql_priv.h"
22#include "key.h" // key_rec_cmp
23#include "field.h" // Field
24
25/*
26 Search after a key that starts with 'field'
27
28 SYNOPSIS
29 find_ref_key()
30 key First key to check
31 key_count How many keys to check
32 record Start of record
33 field Field to search after
34 key_length On partial match, contains length of fields before
35 field
36 keypart key part # of a field
37
38 NOTES
39 Used when calculating key for NEXT_NUMBER
40
41 IMPLEMENTATION
42 If no key starts with field test if field is part of some key. If we find
43 one, then return first key and set key_length to the number of bytes
44 preceding 'field'.
45
46 RETURN
47 -1 field is not part of the key
48 # Key part for key matching key.
49 key_length is set to length of key before (not including) field
50*/
51
52int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field,
53 uint *key_length, uint *keypart)
54{
55 int i;
56 KEY *key_info;
57 uint fieldpos;
58
59 fieldpos= field->offset(record);
60
61 /* Test if some key starts as fieldpos */
62 for (i= 0, key_info= key ;
63 i < (int) key_count ;
64 i++, key_info++)
65 {
66 if (key_info->key_part[0].offset == fieldpos &&
67 key_info->key_part[0].field->type() != MYSQL_TYPE_BIT)
68 { /* Found key. Calc keylength */
69 *key_length= *keypart= 0;
70 return i; /* Use this key */
71 }
72 }
73
74 /* Test if some key contains fieldpos */
75 for (i= 0, key_info= key;
76 i < (int) key_count ;
77 i++, key_info++)
78 {
79 uint j;
80 KEY_PART_INFO *key_part;
81 *key_length=0;
82 for (j=0, key_part=key_info->key_part ;
83 j < key_info->user_defined_key_parts ;
84 j++, key_part++)
85 {
86 if (key_part->offset == fieldpos &&
87 key_part->field->type() != MYSQL_TYPE_BIT)
88 {
89 *keypart= j;
90 return i; /* Use this key */
91 }
92 *key_length+= key_part->store_length;
93 }
94 }
95 return(-1); /* No key is ok */
96}
97
98
99/**
100 Copy part of a record that forms a key or key prefix to a buffer.
101
102 The function takes a complete table record (as e.g. retrieved by
103 handler::index_read()), and a description of an index on the same table,
104 and extracts the first key_length bytes of the record which are part of a
105 key into to_key. If length == 0 then copy all bytes from the record that
106 form a key.
107
108 @param to_key buffer that will be used as a key
109 @param from_record full record to be copied from
110 @param key_info descriptor of the index
111 @param key_length specifies length of all keyparts that will be copied
112 @param with_zerofill skipped bytes in the key buffer to be filled with 0
113*/
114
115void key_copy(uchar *to_key, const uchar *from_record, KEY *key_info,
116 uint key_length, bool with_zerofill)
117{
118 uint length;
119 KEY_PART_INFO *key_part;
120
121 if (key_length == 0)
122 key_length= key_info->key_length;
123 for (key_part= key_info->key_part;
124 (int) key_length > 0;
125 key_part++, to_key+= length, key_length-= length)
126 {
127 if (key_part->null_bit)
128 {
129 *to_key++= MY_TEST(from_record[key_part->null_offset] &
130 key_part->null_bit);
131 key_length--;
132 if (to_key[-1])
133 {
134 /*
135 Don't copy data for null values
136 The -1 below is to subtract the null byte which is already handled
137 */
138 length= MY_MIN(key_length, uint(key_part->store_length)-1);
139 if (with_zerofill)
140 bzero((char*) to_key, length);
141 continue;
142 }
143 }
144 if (key_part->key_part_flag & HA_BLOB_PART ||
145 key_part->key_part_flag & HA_VAR_LENGTH_PART)
146 {
147 key_length-= HA_KEY_BLOB_LENGTH;
148 length= MY_MIN(key_length, key_part->length);
149 uint bytes= key_part->field->get_key_image(to_key, length, Field::itRAW);
150 if (with_zerofill && bytes < length)
151 bzero((char*) to_key + bytes, length - bytes);
152 to_key+= HA_KEY_BLOB_LENGTH;
153 }
154 else
155 {
156 length= MY_MIN(key_length, key_part->length);
157 Field *field= key_part->field;
158 CHARSET_INFO *cs= field->charset();
159 uint bytes= field->get_key_image(to_key, length, Field::itRAW);
160 if (bytes < length)
161 cs->cset->fill(cs, (char*) to_key + bytes, length - bytes, ' ');
162 }
163 }
164}
165
166
167/**
168 Restore a key from some buffer to record.
169
170 This function converts a key into record format. It can be used in cases
171 when we want to return a key as a result row.
172
173 @param to_record record buffer where the key will be restored to
174 @param from_key buffer that contains a key
175 @param key_info descriptor of the index
176 @param key_length specifies length of all keyparts that will be restored
177*/
178
179void key_restore(uchar *to_record, const uchar *from_key, KEY *key_info,
180 uint key_length)
181{
182 uint length;
183 KEY_PART_INFO *key_part;
184
185 if (key_length == 0)
186 {
187 key_length= key_info->key_length;
188 }
189 for (key_part= key_info->key_part ;
190 (int) key_length > 0 ;
191 key_part++, from_key+= length, key_length-= length)
192 {
193 uchar used_uneven_bits= 0;
194 if (key_part->null_bit)
195 {
196 bool null_value;
197 if ((null_value= *from_key++))
198 to_record[key_part->null_offset]|= key_part->null_bit;
199 else
200 to_record[key_part->null_offset]&= ~key_part->null_bit;
201 key_length--;
202 if (null_value)
203 {
204 /*
205 Don't copy data for null bytes
206 The -1 below is to subtract the null byte which is already handled
207 */
208 length= MY_MIN(key_length, uint(key_part->store_length)-1);
209 continue;
210 }
211 }
212 if (key_part->type == HA_KEYTYPE_BIT)
213 {
214 Field_bit *field= (Field_bit *) (key_part->field);
215 if (field->bit_len)
216 {
217 uchar bits= *(from_key + key_part->length -
218 field->pack_length_in_rec() - 1);
219 set_rec_bits(bits, to_record + key_part->null_offset +
220 (key_part->null_bit == 128),
221 field->bit_ofs, field->bit_len);
222 /* we have now used the byte with 'uneven' bits */
223 used_uneven_bits= 1;
224 }
225 }
226 if (key_part->key_part_flag & HA_BLOB_PART)
227 {
228 /*
229 This in fact never happens, as we have only partial BLOB
230 keys yet anyway, so it's difficult to find any sence to
231 restore the part of a record.
232 Maybe this branch is to be removed, but now we
233 have to ignore GCov compaining.
234 */
235 uint blob_length= uint2korr(from_key);
236 Field_blob *field= (Field_blob*) key_part->field;
237 from_key+= HA_KEY_BLOB_LENGTH;
238 key_length-= HA_KEY_BLOB_LENGTH;
239 field->set_ptr_offset(to_record - field->table->record[0],
240 (ulong) blob_length, from_key);
241 length= key_part->length;
242 }
243 else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
244 {
245 Field *field= key_part->field;
246 my_bitmap_map *old_map;
247 my_ptrdiff_t ptrdiff= to_record - field->table->record[0];
248 field->move_field_offset(ptrdiff);
249 key_length-= HA_KEY_BLOB_LENGTH;
250 length= MY_MIN(key_length, key_part->length);
251 old_map= dbug_tmp_use_all_columns(field->table, field->table->write_set);
252 field->set_key_image(from_key, length);
253 dbug_tmp_restore_column_map(field->table->write_set, old_map);
254 from_key+= HA_KEY_BLOB_LENGTH;
255 field->move_field_offset(-ptrdiff);
256 }
257 else
258 {
259 length= MY_MIN(key_length, key_part->length);
260 /* skip the byte with 'uneven' bits, if used */
261 memcpy(to_record + key_part->offset, from_key + used_uneven_bits
262 , (size_t) length - used_uneven_bits);
263 }
264 }
265}
266
267
268/**
269 Compare if a key has changed.
270
271 @param table TABLE
272 @param key key to compare to row
273 @param idx Index used
274 @param key_length Length of key
275
276 @note
277 In theory we could just call field->cmp() for all field types,
278 but as we are only interested if a key has changed (not if the key is
279 larger or smaller than the previous value) we can do things a bit
280 faster by using memcmp() instead.
281
282 @retval
283 0 If key is equal
284 @retval
285 1 Key has changed
286*/
287
288bool key_cmp_if_same(TABLE *table,const uchar *key,uint idx,uint key_length)
289{
290 uint store_length;
291 KEY_PART_INFO *key_part;
292 const uchar *key_end= key + key_length;;
293
294 for (key_part=table->key_info[idx].key_part;
295 key < key_end ;
296 key_part++, key+= store_length)
297 {
298 uint length;
299 store_length= key_part->store_length;
300
301 if (key_part->null_bit)
302 {
303 if (*key != MY_TEST(table->record[0][key_part->null_offset] &
304 key_part->null_bit))
305 return 1;
306 if (*key)
307 continue;
308 key++;
309 store_length--;
310 }
311 if (!(key_part->key_part_flag & HA_CAN_MEMCMP))
312 {
313 if (key_part->field->key_cmp(key, key_part->length))
314 return 1;
315 continue;
316 }
317 length= MY_MIN((uint) (key_end-key), store_length);
318 if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
319 FIELDFLAG_PACK)))
320 {
321 CHARSET_INFO *cs= key_part->field->charset();
322 size_t char_length= key_part->length / cs->mbmaxlen;
323 const uchar *pos= table->record[0] + key_part->offset;
324 if (length > char_length)
325 {
326 char_length= my_charpos(cs, pos, pos + length, char_length);
327 set_if_smaller(char_length, length);
328 }
329 if (cs->coll->strnncollsp(cs,
330 (const uchar*) key, length,
331 (const uchar*) pos, char_length))
332 return 1;
333 continue;
334 }
335 if (memcmp(key,table->record[0]+key_part->offset,length))
336 return 1;
337 }
338 return 0;
339}
340
341
342/**
343 Unpack a field and append it.
344
345 @param[inout] to String to append the field contents to.
346 @param field Field to unpack.
347 @param rec Record which contains the field data.
348 @param max_length Maximum length of field to unpack
349 or 0 for unlimited.
350 @param prefix_key The field is used as a prefix key.
351*/
352
353void field_unpack(String *to, Field *field, const uchar *rec, uint max_length,
354 bool prefix_key)
355{
356 String tmp;
357 DBUG_ENTER("field_unpack");
358 if (!max_length)
359 max_length= field->pack_length();
360 if (field)
361 {
362 if (field->is_null())
363 {
364 to->append(STRING_WITH_LEN("NULL"));
365 DBUG_VOID_RETURN;
366 }
367 CHARSET_INFO *cs= field->charset();
368 field->val_str(&tmp);
369 /*
370 For BINARY(N) strip trailing zeroes to make
371 the error message nice-looking
372 */
373 if (field->binary() && field->type() == MYSQL_TYPE_STRING && tmp.length())
374 {
375 const char *tmp_end= tmp.ptr() + tmp.length();
376 while (tmp_end > tmp.ptr() && !*--tmp_end) ;
377 tmp.length((uint32)(tmp_end - tmp.ptr() + 1));
378 }
379 if (cs->mbmaxlen > 1 && prefix_key)
380 {
381 /*
382 Prefix key, multi-byte charset.
383 For the columns of type CHAR(N), the above val_str()
384 call will return exactly "key_part->length" bytes,
385 which can break a multi-byte characters in the middle.
386 Align, returning not more than "char_length" characters.
387 */
388 size_t charpos, char_length= max_length / cs->mbmaxlen;
389 if ((charpos= my_charpos(cs, tmp.ptr(),
390 tmp.ptr() + tmp.length(),
391 char_length)) < tmp.length())
392 tmp.length(charpos);
393 }
394 if (max_length < field->pack_length())
395 tmp.length(MY_MIN(tmp.length(),max_length));
396 ErrConvString err(&tmp);
397 to->append(err.ptr());
398 }
399 else
400 to->append(STRING_WITH_LEN("???"));
401 DBUG_VOID_RETURN;
402}
403
404
405/*
406 unpack key-fields from record to some buffer.
407
408 This is used mainly to get a good error message. We temporary
409 change the column bitmap so that all columns are readable.
410
411 @param
412 to Store value here in an easy to read form
413 @param
414 table Table to use
415 @param
416 key Key
417*/
418
419void key_unpack(String *to, TABLE *table, KEY *key)
420{
421 my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
422 DBUG_ENTER("key_unpack");
423
424 to->length(0);
425 KEY_PART_INFO *key_part_end= key->key_part + key->user_defined_key_parts;
426 for (KEY_PART_INFO *key_part= key->key_part;
427 key_part < key_part_end;
428 key_part++)
429 {
430 if (key_part->field->invisible > INVISIBLE_USER)
431 continue;
432 if (to->length())
433 to->append('-');
434 if (key_part->null_bit)
435 {
436 if (table->record[0][key_part->null_offset] & key_part->null_bit)
437 {
438 to->append(STRING_WITH_LEN("NULL"));
439 continue;
440 }
441 }
442 field_unpack(to, key_part->field, table->record[0], key_part->length,
443 MY_TEST(key_part->key_part_flag & HA_PART_KEY_SEG));
444 }
445 dbug_tmp_restore_column_map(table->read_set, old_map);
446 DBUG_VOID_RETURN;
447}
448
449
450/*
451 Check if key uses field that is marked in passed field bitmap.
452
453 SYNOPSIS
454 is_key_used()
455 table TABLE object with which keys and fields are associated.
456 idx Key to be checked.
457 fields Bitmap of fields to be checked.
458
459 NOTE
460 This function uses TABLE::tmp_set bitmap so the caller should care
461 about saving/restoring its state if it also uses this bitmap.
462
463 RETURN VALUE
464 TRUE Key uses field from bitmap
465 FALSE Otherwise
466*/
467
468bool is_key_used(TABLE *table, uint idx, const MY_BITMAP *fields)
469{
470 table->mark_columns_used_by_index(idx, &table->tmp_set);
471 return bitmap_is_overlapping(&table->tmp_set, fields);
472}
473
474
475/**
476 Compare key in row to a given key.
477
478 @param key_part Key part handler
479 @param key Key to compare to value in table->record[0]
480 @param key_length length of 'key'
481
482 @return
483 The return value is SIGN(key_in_row - range_key):
484 - 0 Key is equal to range or 'range' == 0 (no range)
485 - -1 Key is less than range
486 - 1 Key is larger than range
487*/
488
489int key_cmp(KEY_PART_INFO *key_part, const uchar *key, uint key_length)
490{
491 uint store_length;
492
493 for (const uchar *end=key + key_length;
494 key < end;
495 key+= store_length, key_part++)
496 {
497 int cmp;
498 store_length= key_part->store_length;
499 if (key_part->null_bit)
500 {
501 /* This key part allows null values; NULL is lower than everything */
502 bool field_is_null= key_part->field->is_null();
503 if (*key) // If range key is null
504 {
505 /* the range is expecting a null value */
506 if (!field_is_null)
507 return 1; // Found key is > range
508 /* null -- exact match, go to next key part */
509 continue;
510 }
511 else if (field_is_null)
512 return -1; // NULL is less than any value
513 key++; // Skip null byte
514 store_length--;
515 }
516 if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0)
517 return -1;
518 if (cmp > 0)
519 return 1;
520 }
521 return 0; // Keys are equal
522}
523
524
525/**
526 Compare two records in index order.
527
528 This method is set-up such that it can be called directly from the
529 priority queue and it is attempted to be optimised as much as possible
530 since this will be called O(N * log N) times while performing a merge
531 sort in various places in the code.
532
533 We retrieve the pointer to table->record[0] using the fact that key_parts
534 have an offset making it possible to calculate the start of the record.
535 We need to get the diff to the compared record since none of the records
536 being compared are stored in table->record[0].
537
538 We first check for NULL values, if there are no NULL values we use
539 a compare method that gets two field pointers and a max length
540 and return the result of the comparison.
541
542 key is a null terminated array, since in some cases (clustered
543 primary key) it must compare more than one index.
544
545 @param key Null terminated array of index information
546 @param first_rec Pointer to record compare with
547 @param second_rec Pointer to record compare against first_rec
548
549 @return Return value is SIGN(first_rec - second_rec)
550 @retval 0 Keys are equal
551 @retval -1 second_rec is greater than first_rec
552 @retval +1 first_rec is greater than second_rec
553*/
554
555int key_rec_cmp(void *key_p, uchar *first_rec, uchar *second_rec)
556{
557 KEY **key= (KEY**) key_p;
558 KEY *key_info= *(key++); // Start with first key
559 uint key_parts, key_part_num;
560 KEY_PART_INFO *key_part= key_info->key_part;
561 uchar *rec0= key_part->field->ptr - key_part->offset;
562 my_ptrdiff_t first_diff= first_rec - rec0, sec_diff= second_rec - rec0;
563 int result= 0;
564 Field *field;
565 DBUG_ENTER("key_rec_cmp");
566
567 /* loop over all given keys */
568 do
569 {
570 key_parts= key_info->user_defined_key_parts;
571 key_part= key_info->key_part;
572 key_part_num= 0;
573
574 /* loop over every key part */
575 do
576 {
577 field= key_part->field;
578
579 if (key_part->null_bit)
580 {
581 /* The key_part can contain NULL values */
582 bool first_is_null= field->is_real_null(first_diff);
583 bool sec_is_null= field->is_real_null(sec_diff);
584 /*
585 NULL is smaller then everything so if first is NULL and the other
586 not then we know that we should return -1 and for the opposite
587 we should return +1. If both are NULL then we call it equality
588 although it is a strange form of equality, we have equally little
589 information of the real value.
590 */
591 if (!first_is_null)
592 {
593 if (!sec_is_null)
594 ; /* Fall through, no NULL fields */
595 else
596 {
597 DBUG_RETURN(+1);
598 }
599 }
600 else if (!sec_is_null)
601 {
602 DBUG_RETURN(-1);
603 }
604 else
605 goto next_loop; /* Both were NULL */
606 }
607 /*
608 No null values in the fields
609 We use the virtual method cmp_max with a max length parameter.
610 For most field types this translates into a cmp without
611 max length. The exceptions are the BLOB and VARCHAR field types
612 that take the max length into account.
613 */
614 if ((result= field->cmp_max(field->ptr+first_diff, field->ptr+sec_diff,
615 key_part->length)))
616 DBUG_RETURN(result);
617next_loop:
618 key_part++;
619 key_part_num++;
620 } while (key_part_num < key_parts); /* this key is done */
621
622 key_info= *(key++);
623 } while (key_info); /* no more keys to test */
624 DBUG_RETURN(0);
625}
626
627
628/*
629 Compare two key tuples.
630
631 @brief
632 Compare two key tuples, i.e. two key values in KeyTupleFormat.
633
634 @param part KEY_PART_INFO with key description
635 @param key1 First key to compare
636 @param key2 Second key to compare
637 @param tuple_length Length of key1 (and key2, they are the same) in bytes.
638
639 @return
640 @retval 0 key1 == key2
641 @retval -1 key1 < key2
642 @retval +1 key1 > key2
643*/
644
645int key_tuple_cmp(KEY_PART_INFO *part, uchar *key1, uchar *key2,
646 uint tuple_length)
647{
648 uchar *key1_end= key1 + tuple_length;
649 int UNINIT_VAR(len);
650 int res;
651 for (;key1 < key1_end; key1 += len, key2 += len, part++)
652 {
653 len= part->store_length;
654 if (part->null_bit)
655 {
656 if (*key1) // key1 == NULL
657 {
658 if (!*key2) // key1(NULL) < key2(notNULL)
659 return -1;
660 continue;
661 }
662 else if (*key2) // key1(notNULL) > key2 (NULL)
663 return 1;
664 /* Step over the NULL bytes for key_cmp() call */
665 key1++;
666 key2++;
667 len--;
668 }
669 if ((res= part->field->key_cmp(key1, key2)))
670 return res;
671 }
672 return 0;
673}
674
675
676/**
677 Get hash value for the key from a key buffer
678
679 @param key_info the key descriptor
680 @param used_key_part number of key parts used for the key
681 @param key pointer to the buffer with the key value
682
683 @datails
684 When hashing we should take special care only of:
685 1. NULLs (and keyparts which can be null so one byte reserved for it);
686 2. Strings for which we have to take into account their collations
687 and the values of their lengths in the prefixes.
688
689 @return hash value calculated for the key
690*/
691
692ulong key_hashnr(KEY *key_info, uint used_key_parts, const uchar *key)
693{
694 ulong nr=1, nr2=4;
695 KEY_PART_INFO *key_part= key_info->key_part;
696 KEY_PART_INFO *end_key_part= key_part + used_key_parts;
697
698 for (; key_part < end_key_part; key_part++)
699 {
700 uchar *pos= (uchar*)key;
701 CHARSET_INFO *UNINIT_VAR(cs);
702 size_t UNINIT_VAR(length), UNINIT_VAR(pack_length);
703 bool is_string= TRUE;
704
705 key+= key_part->length;
706 if (key_part->null_bit)
707 {
708 key++; /* Skip null byte */
709 if (*pos) /* Found null */
710 {
711 nr^= (nr << 1) | 1;
712 /* Add key pack length to key for VARCHAR segments */
713 switch (key_part->type) {
714 case HA_KEYTYPE_VARTEXT1:
715 case HA_KEYTYPE_VARBINARY1:
716 case HA_KEYTYPE_VARTEXT2:
717 case HA_KEYTYPE_VARBINARY2:
718 key+= 2;
719 break;
720 default:
721 ;
722 }
723 continue;
724 }
725 pos++; /* Skip null byte */
726 }
727 /* If it is string set parameters of the string */
728 switch (key_part->type) {
729 case HA_KEYTYPE_TEXT:
730 cs= key_part->field->charset();
731 length= key_part->length;
732 pack_length= 0;
733 break;
734 case HA_KEYTYPE_BINARY :
735 cs= &my_charset_bin;
736 length= key_part->length;
737 pack_length= 0;
738 break;
739 case HA_KEYTYPE_VARTEXT1:
740 case HA_KEYTYPE_VARTEXT2:
741 cs= key_part->field->charset();
742 length= uint2korr(pos);
743 pack_length= 2;
744 break;
745 case HA_KEYTYPE_VARBINARY1:
746 case HA_KEYTYPE_VARBINARY2:
747 cs= &my_charset_bin;
748 length= uint2korr(pos);
749 pack_length= 2;
750 break;
751 default:
752 is_string= FALSE;
753 }
754
755 if (is_string)
756 {
757 if (cs->mbmaxlen > 1)
758 {
759 size_t char_length= my_charpos(cs, pos + pack_length,
760 pos + pack_length + length,
761 length / cs->mbmaxlen);
762 set_if_smaller(length, char_length);
763 }
764 cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2);
765 key+= pack_length;
766 }
767 else
768 {
769 for (; pos < (uchar*)key ; pos++)
770 {
771 nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) *pos)) + (nr << 8);
772 nr2+=3;
773 }
774 }
775 }
776 DBUG_PRINT("exit", ("hash: %lx", nr));
777 return(nr);
778}
779
780
781/**
782 Check whether two keys in the key buffers are equal
783
784 @param key_info the key descriptor
785 @param used_key_part number of key parts used for the keys
786 @param key1 pointer to the buffer with the first key
787 @param key2 pointer to the buffer with the second key
788
789 @detail See details of key_hashnr().
790
791 @retval TRUE keys in the buffers are NOT equal
792 @retval FALSE keys in the buffers are equal
793*/
794
795bool key_buf_cmp(KEY *key_info, uint used_key_parts,
796 const uchar *key1, const uchar *key2)
797{
798 KEY_PART_INFO *key_part= key_info->key_part;
799 KEY_PART_INFO *end_key_part= key_part + used_key_parts;
800
801 for (; key_part < end_key_part; key_part++)
802 {
803 uchar *pos1= (uchar*)key1;
804 uchar *pos2= (uchar*)key2;
805 CHARSET_INFO *UNINIT_VAR(cs);
806 size_t UNINIT_VAR(length1), UNINIT_VAR(length2), UNINIT_VAR(pack_length);
807 bool is_string= TRUE;
808
809 key1+= key_part->length;
810 key2+= key_part->length;
811 if (key_part->null_bit)
812 {
813 key1++; key2++; /* Skip null byte */
814 if (*pos1 && *pos2) /* Both are null */
815 {
816 /* Add key pack length to key for VARCHAR segments */
817 switch (key_part->type) {
818 case HA_KEYTYPE_VARTEXT1:
819 case HA_KEYTYPE_VARBINARY1:
820 case HA_KEYTYPE_VARTEXT2:
821 case HA_KEYTYPE_VARBINARY2:
822 key1+= 2; key2+= 2;
823 break;
824 default:
825 ;
826 }
827 continue;
828 }
829 if (*pos1 != *pos2)
830 return TRUE;
831 pos1++; pos2++;
832 }
833
834 /* If it is string set parameters of the string */
835 switch (key_part->type) {
836 case HA_KEYTYPE_TEXT:
837 cs= key_part->field->charset();
838 length1= length2= key_part->length;
839 pack_length= 0;
840 break;
841 case HA_KEYTYPE_BINARY :
842 cs= &my_charset_bin;
843 length1= length2= key_part->length;
844 pack_length= 0;
845 break;
846 case HA_KEYTYPE_VARTEXT1:
847 case HA_KEYTYPE_VARTEXT2:
848 cs= key_part->field->charset();
849 length1= uint2korr(pos1);
850 length2= uint2korr(pos2);
851 pack_length= 2;
852 break;
853 case HA_KEYTYPE_VARBINARY1:
854 case HA_KEYTYPE_VARBINARY2:
855 cs= &my_charset_bin;
856 length1= uint2korr(pos1);
857 length2= uint2korr(pos2);
858 pack_length= 2;
859 break;
860 default:
861 is_string= FALSE;
862 }
863
864 if (is_string)
865 {
866 /*
867 Compare the strings taking into account length in characters
868 and collation
869 */
870 size_t byte_len1= length1, byte_len2= length2;
871 if (cs->mbmaxlen > 1)
872 {
873 size_t char_length1= my_charpos(cs, pos1 + pack_length,
874 pos1 + pack_length + length1,
875 length1 / cs->mbmaxlen);
876 size_t char_length2= my_charpos(cs, pos2 + pack_length,
877 pos2 + pack_length + length2,
878 length2 / cs->mbmaxlen);
879 set_if_smaller(length1, char_length1);
880 set_if_smaller(length2, char_length2);
881 }
882 if (length1 != length2 ||
883 cs->coll->strnncollsp(cs,
884 pos1 + pack_length, byte_len1,
885 pos2 + pack_length, byte_len2))
886 return TRUE;
887 key1+= pack_length; key2+= pack_length;
888 }
889 else
890 {
891 /* it is OK to compare non-string byte per byte */
892 for (; pos1 < (uchar*)key1 ; pos1++, pos2++)
893 {
894 if (pos1[0] != pos2[0])
895 return TRUE;
896 }
897 }
898 }
899 return FALSE;
900}
901