MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
my_compare.c
1 /* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
15 
16 #include <my_global.h>
17 #include <m_ctype.h>
18 #include <my_base.h>
19 #include <my_compare.h>
20 #include <my_sys.h>
21 
22 #define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1)
23 
24 int ha_compare_text(const CHARSET_INFO *charset_info, uchar *a, uint a_length,
25  uchar *b, uint b_length, my_bool part_key,
26  my_bool skip_end_space)
27 {
28  if (!part_key)
29  return charset_info->coll->strnncollsp(charset_info, a, a_length,
30  b, b_length, (my_bool)!skip_end_space);
31  return charset_info->coll->strnncoll(charset_info, a, a_length,
32  b, b_length, part_key);
33 }
34 
35 
36 static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
37  my_bool part_key, my_bool skip_end_space)
38 {
39  uint length= MY_MIN(a_length, b_length);
40  uchar *end= a+ length;
41  int flag;
42 
43  while (a < end)
44  if ((flag= (int) *a++ - (int) *b++))
45  return flag;
46  if (part_key && b_length < a_length)
47  return 0;
48  if (skip_end_space && a_length != b_length)
49  {
50  int swap= 1;
51  /*
52  We are using space compression. We have to check if longer key
53  has next character < ' ', in which case it's less than the shorter
54  key that has an implicite space afterwards.
55 
56  This code is identical to the one in
57  strings/ctype-simple.c:my_strnncollsp_simple
58  */
59  if (a_length < b_length)
60  {
61  /* put shorter key in a */
62  a_length= b_length;
63  a= b;
64  swap= -1; /* swap sign of result */
65  }
66  for (end= a + a_length-length; a < end ; a++)
67  {
68  if (*a != ' ')
69  return (*a < ' ') ? -swap : swap;
70  }
71  return 0;
72  }
73  return (int) (a_length-b_length);
74 }
75 
76 
77 /*
78  Compare two keys
79 
80  SYNOPSIS
81  ha_key_cmp()
82  keyseg Array of key segments of key to compare
83  a First key to compare, in format from _mi_pack_key()
84  This is normally key specified by user
85  b Second key to compare. This is always from a row
86  key_length Length of key to compare. This can be shorter than
87  a to just compare sub keys
88  next_flag How keys should be compared
89  If bit SEARCH_FIND is not set the keys includes the row
90  position and this should also be compared
91  diff_pos OUT Number of first keypart where values differ, counting
92  from one.
93  diff_pos[1] OUT (b + diff_pos[1]) points to first value in tuple b
94  that is different from corresponding value in tuple a.
95 
96  EXAMPLES
97  Example1: if the function is called for tuples
98  ('aaa','bbb') and ('eee','fff'), then
99  diff_pos[0] = 1 (as 'aaa' != 'eee')
100  diff_pos[1] = 0 (offset from beggining of tuple b to 'eee' keypart).
101 
102  Example2: if the index function is called for tuples
103  ('aaa','bbb') and ('aaa','fff'),
104  diff_pos[0] = 2 (as 'aaa' != 'eee')
105  diff_pos[1] = 3 (offset from beggining of tuple b to 'fff' keypart,
106  here we assume that first key part is CHAR(3) NOT NULL)
107 
108  NOTES
109  Number-keys can't be splited
110 
111  RETURN VALUES
112  <0 If a < b
113  0 If a == b
114  >0 If a > b
115 */
116 
117 #define FCMP(A,B) ((int) (A) - (int) (B))
118 
119 int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
120  register uchar *b, uint key_length, uint nextflag,
121  uint *diff_pos)
122 {
123  int flag;
124  int16 s_1,s_2;
125  int32 l_1,l_2;
126  uint32 u_1,u_2;
127  float f_1,f_2;
128  double d_1,d_2;
129  uint next_key_length;
130  uchar *orig_b= b;
131 
132  *diff_pos=0;
133  for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++)
134  {
135  uchar *end;
136  uint piks=! (keyseg->flag & HA_NO_SORT);
137  (*diff_pos)++;
138  diff_pos[1]= (uint)(b - orig_b);
139 
140  /* Handle NULL part */
141  if (keyseg->null_bit)
142  {
143  key_length--;
144  if (*a != *b && piks)
145  {
146  flag = (int) *a - (int) *b;
147  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
148  }
149  b++;
150  if (!*a++) /* If key was NULL */
151  {
152  if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
153  nextflag=SEARCH_SAME; /* Allow duplicate keys */
154  else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL)
155  {
156  /*
157  This is only used from mi_check() to calculate cardinality.
158  It can't be used when searching for a key as this would cause
159  compare of (a,b) and (b,a) to return the same value.
160  */
161  return -1;
162  }
163  next_key_length=key_length;
164  continue; /* To next key part */
165  }
166  }
167  end= a + MY_MIN(keyseg->length, key_length);
168  next_key_length=key_length-keyseg->length;
169 
170  switch ((enum ha_base_keytype) keyseg->type) {
171  case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
172  if (keyseg->flag & HA_SPACE_PACK)
173  {
174  int a_length,b_length,pack_length;
175  get_key_length(a_length,a);
176  get_key_pack_length(b_length,pack_length,b);
177  next_key_length=key_length-b_length-pack_length;
178 
179  if (piks &&
180  (flag=ha_compare_text(keyseg->charset,a,a_length,b,b_length,
181  (my_bool) ((nextflag & SEARCH_PREFIX) &&
182  next_key_length <= 0),
183  (my_bool)!(nextflag & SEARCH_PREFIX))))
184  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
185  a+=a_length;
186  b+=b_length;
187  break;
188  }
189  else
190  {
191  uint length=(uint) (end-a), a_length=length, b_length=length;
192  if (piks &&
193  (flag= ha_compare_text(keyseg->charset, a, a_length, b, b_length,
194  (my_bool) ((nextflag & SEARCH_PREFIX) &&
195  next_key_length <= 0),
196  (my_bool)!(nextflag & SEARCH_PREFIX))))
197  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
198  a=end;
199  b+=length;
200  }
201  break;
202  case HA_KEYTYPE_BINARY:
203  case HA_KEYTYPE_BIT:
204  if (keyseg->flag & HA_SPACE_PACK)
205  {
206  int a_length,b_length,pack_length;
207  get_key_length(a_length,a);
208  get_key_pack_length(b_length,pack_length,b);
209  next_key_length=key_length-b_length-pack_length;
210 
211  if (piks &&
212  (flag=compare_bin(a,a_length,b,b_length,
213  (my_bool) ((nextflag & SEARCH_PREFIX) &&
214  next_key_length <= 0),1)))
215  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
216  a+=a_length;
217  b+=b_length;
218  break;
219  }
220  else
221  {
222  uint length=keyseg->length;
223  if (piks &&
224  (flag=compare_bin(a,length,b,length,
225  (my_bool) ((nextflag & SEARCH_PREFIX) &&
226  next_key_length <= 0),0)))
227  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
228  a+=length;
229  b+=length;
230  }
231  break;
232  case HA_KEYTYPE_VARTEXT1:
233  case HA_KEYTYPE_VARTEXT2:
234  {
235  int a_length,b_length,pack_length;
236  get_key_length(a_length,a);
237  get_key_pack_length(b_length,pack_length,b);
238  next_key_length=key_length-b_length-pack_length;
239 
240  if (piks &&
241  (flag= ha_compare_text(keyseg->charset,a,a_length,b,b_length,
242  (my_bool) ((nextflag & SEARCH_PREFIX) &&
243  next_key_length <= 0),
244  (my_bool) ((nextflag & (SEARCH_FIND |
245  SEARCH_UPDATE)) ==
246  SEARCH_FIND &&
247  ! (keyseg->flag &
248  HA_END_SPACE_ARE_EQUAL)))))
249  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
250  a+= a_length;
251  b+= b_length;
252  break;
253  }
254  break;
255  case HA_KEYTYPE_VARBINARY1:
256  case HA_KEYTYPE_VARBINARY2:
257  {
258  int a_length,b_length,pack_length;
259  get_key_length(a_length,a);
260  get_key_pack_length(b_length,pack_length,b);
261  next_key_length=key_length-b_length-pack_length;
262 
263  if (piks &&
264  (flag=compare_bin(a,a_length,b,b_length,
265  (my_bool) ((nextflag & SEARCH_PREFIX) &&
266  next_key_length <= 0), 0)))
267  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
268  a+=a_length;
269  b+=b_length;
270  }
271  break;
272  case HA_KEYTYPE_INT8:
273  {
274  int i_1= (int) *((signed char*) a);
275  int i_2= (int) *((signed char*) b);
276  if (piks && (flag = CMP_NUM(i_1,i_2)))
277  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
278  a= end;
279  b++;
280  break;
281  }
282  case HA_KEYTYPE_SHORT_INT:
283  s_1= mi_sint2korr(a);
284  s_2= mi_sint2korr(b);
285  if (piks && (flag = CMP_NUM(s_1,s_2)))
286  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
287  a= end;
288  b+= 2; /* sizeof(short int); */
289  break;
290  case HA_KEYTYPE_USHORT_INT:
291  {
292  uint16 us_1,us_2;
293  us_1= mi_sint2korr(a);
294  us_2= mi_sint2korr(b);
295  if (piks && (flag = CMP_NUM(us_1,us_2)))
296  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
297  a= end;
298  b+=2; /* sizeof(short int); */
299  break;
300  }
301  case HA_KEYTYPE_LONG_INT:
302  l_1= mi_sint4korr(a);
303  l_2= mi_sint4korr(b);
304  if (piks && (flag = CMP_NUM(l_1,l_2)))
305  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
306  a= end;
307  b+= 4; /* sizeof(long int); */
308  break;
309  case HA_KEYTYPE_ULONG_INT:
310  u_1= mi_sint4korr(a);
311  u_2= mi_sint4korr(b);
312  if (piks && (flag = CMP_NUM(u_1,u_2)))
313  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
314  a= end;
315  b+= 4; /* sizeof(long int); */
316  break;
317  case HA_KEYTYPE_INT24:
318  l_1=mi_sint3korr(a);
319  l_2=mi_sint3korr(b);
320  if (piks && (flag = CMP_NUM(l_1,l_2)))
321  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
322  a= end;
323  b+= 3;
324  break;
325  case HA_KEYTYPE_UINT24:
326  l_1=mi_uint3korr(a);
327  l_2=mi_uint3korr(b);
328  if (piks && (flag = CMP_NUM(l_1,l_2)))
329  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
330  a= end;
331  b+= 3;
332  break;
333  case HA_KEYTYPE_FLOAT:
334  mi_float4get(f_1,a);
335  mi_float4get(f_2,b);
336  /*
337  The following may give a compiler warning about floating point
338  comparison not being safe, but this is ok in this context as
339  we are bascily doing sorting
340  */
341  if (piks && (flag = CMP_NUM(f_1,f_2)))
342  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
343  a= end;
344  b+= 4; /* sizeof(float); */
345  break;
346  case HA_KEYTYPE_DOUBLE:
347  mi_float8get(d_1,a);
348  mi_float8get(d_2,b);
349  /*
350  The following may give a compiler warning about floating point
351  comparison not being safe, but this is ok in this context as
352  we are bascily doing sorting
353  */
354  if (piks && (flag = CMP_NUM(d_1,d_2)))
355  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
356  a= end;
357  b+= 8; /* sizeof(double); */
358  break;
359  case HA_KEYTYPE_NUM: /* Numeric key */
360  {
361  int swap_flag= 0;
362  int alength,blength;
363 
364  if (keyseg->flag & HA_REVERSE_SORT)
365  {
366  swap_variables(uchar*, a, b);
367  swap_flag=1; /* Remember swap of a & b */
368  end= a+ (int) (end-b);
369  }
370  if (keyseg->flag & HA_SPACE_PACK)
371  {
372  alength= *a++; blength= *b++;
373  end=a+alength;
374  next_key_length=key_length-blength-1;
375  }
376  else
377  {
378  alength= (int) (end-a);
379  blength=keyseg->length;
380  /* remove pre space from keys */
381  for ( ; alength && *a == ' ' ; a++, alength--) ;
382  for ( ; blength && *b == ' ' ; b++, blength--) ;
383  }
384  if (piks)
385  {
386  if (*a == '-')
387  {
388  if (*b != '-')
389  return -1;
390  a++; b++;
391  swap_variables(uchar*, a, b);
392  swap_variables(int, alength, blength);
393  swap_flag=1-swap_flag;
394  alength--; blength--;
395  end=a+alength;
396  }
397  else if (*b == '-')
398  return 1;
399  while (alength && (*a == '+' || *a == '0'))
400  {
401  a++; alength--;
402  }
403  while (blength && (*b == '+' || *b == '0'))
404  {
405  b++; blength--;
406  }
407  if (alength != blength)
408  return (alength < blength) ? -1 : 1;
409  while (a < end)
410  if (*a++ != *b++)
411  return ((int) a[-1] - (int) b[-1]);
412  }
413  else
414  {
415  b+=(end-a);
416  a=end;
417  }
418 
419  if (swap_flag) /* Restore pointers */
420  swap_variables(uchar*, a, b);
421  break;
422  }
423 #ifdef HAVE_LONG_LONG
424  case HA_KEYTYPE_LONGLONG:
425  {
426  longlong ll_a,ll_b;
427  ll_a= mi_sint8korr(a);
428  ll_b= mi_sint8korr(b);
429  if (piks && (flag = CMP_NUM(ll_a,ll_b)))
430  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
431  a= end;
432  b+= 8;
433  break;
434  }
435  case HA_KEYTYPE_ULONGLONG:
436  {
437  ulonglong ll_a,ll_b;
438  ll_a= mi_uint8korr(a);
439  ll_b= mi_uint8korr(b);
440  if (piks && (flag = CMP_NUM(ll_a,ll_b)))
441  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
442  a= end;
443  b+= 8;
444  break;
445  }
446 #endif
447  case HA_KEYTYPE_END: /* Ready */
448  goto end; /* diff_pos is incremented */
449  }
450  }
451  (*diff_pos)++;
452 end:
453  if (!(nextflag & SEARCH_FIND))
454  {
455  uint i;
456  if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
457  return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
458  flag=0;
459  for (i=keyseg->length ; i-- > 0 ; )
460  {
461  if (*a++ != *b++)
462  {
463  flag= FCMP(a[-1],b[-1]);
464  break;
465  }
466  }
467  if (nextflag & SEARCH_SAME)
468  return (flag); /* read same */
469  if (nextflag & SEARCH_BIGGER)
470  return (flag <= 0 ? -1 : 1); /* read next */
471  return (flag < 0 ? -1 : 1); /* read previous */
472  }
473  return 0;
474 } /* ha_key_cmp */
475 
476