1
/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
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.
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.
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 */
16
#include "my_compare.h"
18
int ha_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
19
uchar *b, uint b_length, my_bool part_key,
20
my_bool skip_end_space)
23
return charset_info->coll->strnncollsp(charset_info, a, a_length,
24
b, b_length, (my_bool)!skip_end_space);
25
return charset_info->coll->strnncoll(charset_info, a, a_length,
26
b, b_length, part_key);
30
static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
31
my_bool part_key, my_bool skip_end_space)
33
uint length= min(a_length,b_length);
34
uchar *end= a+ length;
38
if ((flag= (int) *a++ - (int) *b++))
40
if (part_key && b_length < a_length)
42
if (skip_end_space && a_length != b_length)
46
We are using space compression. We have to check if longer key
47
has next character < ' ', in which case it's less than the shorter
48
key that has an implicite space afterwards.
50
This code is identical to the one in
51
strings/ctype-simple.c:my_strnncollsp_simple
53
if (a_length < b_length)
55
/* put shorter key in a */
58
swap= -1; /* swap sign of result */
60
for (end= a + a_length-length; a < end ; a++)
63
return (*a < ' ') ? -swap : swap;
67
return (int) (a_length-b_length);
76
keyseg Array of key segments of key to compare
77
a First key to compare, in format from _mi_pack_key()
78
This is normally key specified by user
79
b Second key to compare. This is always from a row
80
key_length Length of key to compare. This can be shorter than
81
a to just compare sub keys
82
next_flag How keys should be compared
83
If bit SEARCH_FIND is not set the keys includes the row
84
position and this should also be compared
85
diff_pos OUT Number of first keypart where values differ, counting
87
diff_pos[1] OUT (b + diff_pos[1]) points to first value in tuple b
88
that is different from corresponding value in tuple a.
91
Example1: if the function is called for tuples
92
('aaa','bbb') and ('eee','fff'), then
93
diff_pos[0] = 1 (as 'aaa' != 'eee')
94
diff_pos[1] = 0 (offset from beggining of tuple b to 'eee' keypart).
96
Example2: if the index function is called for tuples
97
('aaa','bbb') and ('aaa','fff'),
98
diff_pos[0] = 2 (as 'aaa' != 'eee')
99
diff_pos[1] = 3 (offset from beggining of tuple b to 'fff' keypart,
100
here we assume that first key part is CHAR(3) NOT NULL)
103
Number-keys can't be splited
111
#define FCMP(A,B) ((int) (A) - (int) (B))
113
int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
114
register uchar *b, uint key_length, uint nextflag,
123
uint next_key_length;
127
for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++)
130
uint piks=! (keyseg->flag & HA_NO_SORT);
132
diff_pos[1]= (uint)(b - orig_b);
134
/* Handle NULL part */
135
if (keyseg->null_bit)
138
if (*a != *b && piks)
140
flag = (int) *a - (int) *b;
141
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
144
if (!*a++) /* If key was NULL */
146
if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
147
nextflag=SEARCH_SAME; /* Allow duplicate keys */
148
else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL)
151
This is only used from mi_check() to calculate cardinality.
152
It can't be used when searching for a key as this would cause
153
compare of (a,b) and (b,a) to return the same value.
157
next_key_length=key_length;
158
continue; /* To next key part */
161
end= a+ min(keyseg->length,key_length);
162
next_key_length=key_length-keyseg->length;
164
switch ((enum ha_base_keytype) keyseg->type) {
165
case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
166
if (keyseg->flag & HA_SPACE_PACK)
168
int a_length,b_length,pack_length;
169
get_key_length(a_length,a);
170
get_key_pack_length(b_length,pack_length,b);
171
next_key_length=key_length-b_length-pack_length;
174
(flag=ha_compare_text(keyseg->charset,a,a_length,b,b_length,
175
(my_bool) ((nextflag & SEARCH_PREFIX) &&
176
next_key_length <= 0),
177
(my_bool)!(nextflag & SEARCH_PREFIX))))
178
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
185
uint length=(uint) (end-a), a_length=length, b_length=length;
187
(flag= ha_compare_text(keyseg->charset, a, a_length, b, b_length,
188
(my_bool) ((nextflag & SEARCH_PREFIX) &&
189
next_key_length <= 0),
190
(my_bool)!(nextflag & SEARCH_PREFIX))))
191
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
196
case HA_KEYTYPE_BINARY:
198
if (keyseg->flag & HA_SPACE_PACK)
200
int a_length,b_length,pack_length;
201
get_key_length(a_length,a);
202
get_key_pack_length(b_length,pack_length,b);
203
next_key_length=key_length-b_length-pack_length;
206
(flag=compare_bin(a,a_length,b,b_length,
207
(my_bool) ((nextflag & SEARCH_PREFIX) &&
208
next_key_length <= 0),1)))
209
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
216
uint length=keyseg->length;
218
(flag=compare_bin(a,length,b,length,
219
(my_bool) ((nextflag & SEARCH_PREFIX) &&
220
next_key_length <= 0),0)))
221
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
226
case HA_KEYTYPE_VARTEXT1:
227
case HA_KEYTYPE_VARTEXT2:
229
int a_length,b_length,pack_length;
230
get_key_length(a_length,a);
231
get_key_pack_length(b_length,pack_length,b);
232
next_key_length=key_length-b_length-pack_length;
235
(flag= ha_compare_text(keyseg->charset,a,a_length,b,b_length,
236
(my_bool) ((nextflag & SEARCH_PREFIX) &&
237
next_key_length <= 0),
238
(my_bool) ((nextflag & (SEARCH_FIND |
242
HA_END_SPACE_ARE_EQUAL)))))
243
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
249
case HA_KEYTYPE_VARBINARY1:
250
case HA_KEYTYPE_VARBINARY2:
252
int a_length,b_length,pack_length;
253
get_key_length(a_length,a);
254
get_key_pack_length(b_length,pack_length,b);
255
next_key_length=key_length-b_length-pack_length;
258
(flag=compare_bin(a,a_length,b,b_length,
259
(my_bool) ((nextflag & SEARCH_PREFIX) &&
260
next_key_length <= 0), 0)))
261
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
267
case HA_KEYTYPE_INT8:
269
int i_1= (int) *((signed char*) a);
270
int i_2= (int) *((signed char*) b);
271
if (piks && (flag = CMP_NUM(i_1,i_2)))
272
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
277
case HA_KEYTYPE_SHORT_INT:
278
s_1= mi_sint2korr(a);
279
s_2= mi_sint2korr(b);
280
if (piks && (flag = CMP_NUM(s_1,s_2)))
281
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
283
b+= 2; /* sizeof(short int); */
285
case HA_KEYTYPE_USHORT_INT:
288
us_1= mi_sint2korr(a);
289
us_2= mi_sint2korr(b);
290
if (piks && (flag = CMP_NUM(us_1,us_2)))
291
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
293
b+=2; /* sizeof(short int); */
296
case HA_KEYTYPE_LONG_INT:
297
l_1= mi_sint4korr(a);
298
l_2= mi_sint4korr(b);
299
if (piks && (flag = CMP_NUM(l_1,l_2)))
300
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
302
b+= 4; /* sizeof(long int); */
304
case HA_KEYTYPE_ULONG_INT:
305
u_1= mi_sint4korr(a);
306
u_2= mi_sint4korr(b);
307
if (piks && (flag = CMP_NUM(u_1,u_2)))
308
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
310
b+= 4; /* sizeof(long int); */
312
case HA_KEYTYPE_INT24:
315
if (piks && (flag = CMP_NUM(l_1,l_2)))
316
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
320
case HA_KEYTYPE_UINT24:
323
if (piks && (flag = CMP_NUM(l_1,l_2)))
324
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
328
case HA_KEYTYPE_FLOAT:
332
The following may give a compiler warning about floating point
333
comparison not being safe, but this is ok in this context as
334
we are bascily doing sorting
336
if (piks && (flag = CMP_NUM(f_1,f_2)))
337
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
339
b+= 4; /* sizeof(float); */
341
case HA_KEYTYPE_DOUBLE:
345
The following may give a compiler warning about floating point
346
comparison not being safe, but this is ok in this context as
347
we are bascily doing sorting
349
if (piks && (flag = CMP_NUM(d_1,d_2)))
350
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
352
b+= 8; /* sizeof(double); */
354
case HA_KEYTYPE_NUM: /* Numeric key */
359
if (keyseg->flag & HA_REVERSE_SORT)
361
swap_variables(uchar*, a, b);
362
swap_flag=1; /* Remember swap of a & b */
363
end= a+ (int) (end-b);
365
if (keyseg->flag & HA_SPACE_PACK)
367
alength= *a++; blength= *b++;
369
next_key_length=key_length-blength-1;
373
alength= (int) (end-a);
374
blength=keyseg->length;
375
/* remove pre space from keys */
376
for ( ; alength && *a == ' ' ; a++, alength--) ;
377
for ( ; blength && *b == ' ' ; b++, blength--) ;
386
swap_variables(uchar*, a, b);
387
swap_variables(int, alength, blength);
388
swap_flag=1-swap_flag;
389
alength--; blength--;
394
while (alength && (*a == '+' || *a == '0'))
398
while (blength && (*b == '+' || *b == '0'))
402
if (alength != blength)
403
return (alength < blength) ? -1 : 1;
406
return ((int) a[-1] - (int) b[-1]);
414
if (swap_flag) /* Restore pointers */
415
swap_variables(uchar*, a, b);
418
#ifdef HAVE_LONG_LONG
419
case HA_KEYTYPE_LONGLONG:
422
ll_a= mi_sint8korr(a);
423
ll_b= mi_sint8korr(b);
424
if (piks && (flag = CMP_NUM(ll_a,ll_b)))
425
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
430
case HA_KEYTYPE_ULONGLONG:
433
ll_a= mi_uint8korr(a);
434
ll_b= mi_uint8korr(b);
435
if (piks && (flag = CMP_NUM(ll_a,ll_b)))
436
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
442
case HA_KEYTYPE_END: /* Ready */
443
goto end; /* diff_pos is incremented */
448
if (!(nextflag & SEARCH_FIND))
451
if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
452
return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
454
for (i=keyseg->length ; i-- > 0 ; )
458
flag= FCMP(a[-1],b[-1]);
462
if (nextflag & SEARCH_SAME)
463
return (flag); /* read same */
464
if (nextflag & SEARCH_BIGGER)
465
return (flag <= 0 ? -1 : 1); /* read next */
466
return (flag < 0 ? -1 : 1); /* read previous */