Drizzled Public API Documentation

my_handler.cc
1 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2008 Sun Microsystems, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #include <config.h>
21 
22 #include <drizzled/charset.h>
23 #include <drizzled/base.h>
24 #include <plugin/myisam/my_handler.h>
25 #include <drizzled/internal/my_sys.h>
26 
27 #include <cassert>
28 #include <algorithm>
29 
30 using namespace drizzled;
31 using namespace std;
32 
33 template<class T>
34 int CMP_NUM(const T& a, const T&b)
35 {
36  return (a < b) ? -1 : (a == b) ? 0 : 1;
37 }
38 
39 
40 int ha_compare_text(const charset_info_st * const charset_info, unsigned char *a, uint32_t a_length,
41  unsigned char *b, uint32_t b_length, bool part_key,
42  bool skip_end_space)
43 {
44  if (!part_key)
45  return charset_info->coll->strnncollsp(charset_info, a, a_length,
46  b, b_length, (bool)!skip_end_space);
47  return charset_info->coll->strnncoll(charset_info, a, a_length,
48  b, b_length, part_key);
49 }
50 
51 
52 static int compare_bin(unsigned char *a, uint32_t a_length, unsigned char *b, uint32_t b_length,
53  bool part_key, bool skip_end_space)
54 {
55  uint32_t length= min(a_length,b_length);
56  unsigned char *end= a+ length;
57  int flag;
58 
59  while (a < end)
60  if ((flag= (int) *a++ - (int) *b++))
61  return flag;
62  if (part_key && b_length < a_length)
63  return 0;
64  if (skip_end_space && a_length != b_length)
65  {
66  int swap= 1;
67  /*
68  We are using space compression. We have to check if longer key
69  has next character < ' ', in which case it's less than the shorter
70  key that has an implicite space afterwards.
71 
72  This code is identical to the one in
73  strings/ctype-simple.c:my_strnncollsp_simple
74  */
75  if (a_length < b_length)
76  {
77  /* put shorter key in a */
78  a_length= b_length;
79  a= b;
80  swap= -1; /* swap sign of result */
81  }
82  for (end= a + a_length-length; a < end ; a++)
83  {
84  if (*a != ' ')
85  return (*a < ' ') ? -swap : swap;
86  }
87  return 0;
88  }
89  return (int) (a_length-b_length);
90 }
91 
92 
93 /*
94  Compare two keys
95 
96  SYNOPSIS
97  ha_key_cmp()
98  keyseg Array of key segments of key to compare
99  a First key to compare, in format from _mi_pack_key()
100  This is normally key specified by user
101  b Second key to compare. This is always from a row
102  key_length Length of key to compare. This can be shorter than
103  a to just compare sub keys
104  next_flag How keys should be compared
105  If bit SEARCH_FIND is not set the keys includes the row
106  position and this should also be compared
107  diff_pos OUT Number of first keypart where values differ, counting
108  from one.
109  diff_pos[1] OUT (b + diff_pos[1]) points to first value in tuple b
110  that is different from corresponding value in tuple a.
111 
112  EXAMPLES
113  Example1: if the function is called for tuples
114  ('aaa','bbb') and ('eee','fff'), then
115  diff_pos[0] = 1 (as 'aaa' != 'eee')
116  diff_pos[1] = 0 (offset from beggining of tuple b to 'eee' keypart).
117 
118  Example2: if the index function is called for tuples
119  ('aaa','bbb') and ('aaa','fff'),
120  diff_pos[0] = 2 (as 'aaa' != 'eee')
121  diff_pos[1] = 3 (offset from beggining of tuple b to 'fff' keypart,
122  here we assume that first key part is CHAR(3) NOT NULL)
123 
124  NOTES
125  Number-keys can't be splited
126 
127  RETURN VALUES
128  <0 If a < b
129  0 If a == b
130  >0 If a > b
131 */
132 
133 #define FCMP(A,B) ((int) (A) - (int) (B))
134 
135 int ha_key_cmp(register HA_KEYSEG *keyseg, register unsigned char *a,
136  register unsigned char *b, uint32_t key_length, uint32_t nextflag,
137  uint32_t *diff_pos)
138 {
139  int flag;
140  int32_t l_1,l_2;
141  uint32_t u_1,u_2;
142  double d_1,d_2;
143  uint32_t next_key_length;
144  unsigned char *orig_b= b;
145 
146  *diff_pos=0;
147  for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++)
148  {
149  unsigned char *end;
150  uint32_t piks=! (keyseg->flag & HA_NO_SORT);
151  (*diff_pos)++;
152  diff_pos[1]= (uint)(b - orig_b);
153 
154  /* Handle NULL part */
155  if (keyseg->null_bit)
156  {
157  key_length--;
158  if (*a != *b && piks)
159  {
160  flag = (int) *a - (int) *b;
161  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
162  }
163  b++;
164  if (!*a++) /* If key was NULL */
165  {
166  if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
167  nextflag=SEARCH_SAME; /* Allow duplicate keys */
168  else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL)
169  {
170  /*
171  This is only used from mi_check() to calculate cardinality.
172  It can't be used when searching for a key as this would cause
173  compare of (a,b) and (b,a) to return the same value.
174  */
175  return -1;
176  }
177  next_key_length=key_length;
178  continue; /* To next key part */
179  }
180  }
181  end= a+ min((uint32_t)keyseg->length,key_length);
182  next_key_length=key_length-keyseg->length;
183 
184  switch ((enum ha_base_keytype) keyseg->type) {
185  case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
186  if (keyseg->flag & HA_SPACE_PACK)
187  {
188  int a_length,b_length,pack_length;
189  get_key_length(a_length,a);
190  get_key_pack_length(b_length,pack_length,b);
191  next_key_length=key_length-b_length-pack_length;
192 
193  if (piks &&
194  (flag=ha_compare_text(keyseg->charset,a,a_length,b,b_length,
195  (bool) ((nextflag & SEARCH_PREFIX) &&
196  next_key_length <= 0),
197  (bool)!(nextflag & SEARCH_PREFIX))))
198  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
199  a+=a_length;
200  b+=b_length;
201  break;
202  }
203  else
204  {
205  uint32_t length=(uint) (end-a), a_length=length, b_length=length;
206  if (piks &&
207  (flag= ha_compare_text(keyseg->charset, a, a_length, b, b_length,
208  (bool) ((nextflag & SEARCH_PREFIX) &&
209  next_key_length <= 0),
210  (bool)!(nextflag & SEARCH_PREFIX))))
211  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
212  a=end;
213  b+=length;
214  }
215  break;
216  case HA_KEYTYPE_BINARY:
217  if (keyseg->flag & HA_SPACE_PACK)
218  {
219  int a_length,b_length,pack_length;
220  get_key_length(a_length,a);
221  get_key_pack_length(b_length,pack_length,b);
222  next_key_length=key_length-b_length-pack_length;
223 
224  if (piks &&
225  (flag=compare_bin(a,a_length,b,b_length,
226  (bool) ((nextflag & SEARCH_PREFIX) &&
227  next_key_length <= 0),1)))
228  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
229  a+=a_length;
230  b+=b_length;
231  break;
232  }
233  else
234  {
235  uint32_t length=keyseg->length;
236  if (piks &&
237  (flag=compare_bin(a,length,b,length,
238  (bool) ((nextflag & SEARCH_PREFIX) &&
239  next_key_length <= 0),0)))
240  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
241  a+=length;
242  b+=length;
243  }
244  break;
245  case HA_KEYTYPE_VARTEXT1:
246  case HA_KEYTYPE_VARTEXT2:
247  {
248  int a_length,b_length,pack_length;
249  get_key_length(a_length,a);
250  get_key_pack_length(b_length,pack_length,b);
251  next_key_length=key_length-b_length-pack_length;
252 
253  if (piks &&
254  (flag= ha_compare_text(keyseg->charset,a,a_length,b,b_length,
255  (bool) ((nextflag & SEARCH_PREFIX) &&
256  next_key_length <= 0),
257  (bool) ((nextflag & (SEARCH_FIND |
258  SEARCH_UPDATE)) ==
259  SEARCH_FIND &&
260  ! (keyseg->flag &
261  HA_END_SPACE_ARE_EQUAL)))))
262  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
263  a+= a_length;
264  b+= b_length;
265  break;
266  }
267  case HA_KEYTYPE_VARBINARY1:
268  case HA_KEYTYPE_VARBINARY2:
269  {
270  int a_length,b_length,pack_length;
271  get_key_length(a_length,a);
272  get_key_pack_length(b_length,pack_length,b);
273  next_key_length=key_length-b_length-pack_length;
274 
275  if (piks &&
276  (flag=compare_bin(a,a_length,b,b_length,
277  (bool) ((nextflag & SEARCH_PREFIX) &&
278  next_key_length <= 0), 0)))
279  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
280  a+=a_length;
281  b+=b_length;
282  break;
283  }
284  case HA_KEYTYPE_LONG_INT:
285  l_1= mi_sint4korr(a);
286  l_2= mi_sint4korr(b);
287  if (piks && (flag = CMP_NUM(l_1,l_2)))
288  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
289  a= end;
290  b+= 4; /* sizeof(long int); */
291  break;
292  case HA_KEYTYPE_ULONG_INT:
293  u_1= mi_sint4korr(a);
294  u_2= mi_sint4korr(b);
295  if (piks && (flag = CMP_NUM(u_1,u_2)))
296  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
297  a= end;
298  b+= 4; /* sizeof(long int); */
299  break;
300  case HA_KEYTYPE_DOUBLE:
301  mi_float8get(d_1,a);
302  mi_float8get(d_2,b);
303  /*
304  The following may give a compiler warning about floating point
305  comparison not being safe, but this is ok in this context as
306  we are bascily doing sorting
307  */
308  if (piks && (flag = CMP_NUM(d_1,d_2)))
309  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
310  a= end;
311  b+= 8; /* sizeof(double); */
312  break;
313  case HA_KEYTYPE_LONGLONG:
314  {
315  int64_t ll_a,ll_b;
316  ll_a= mi_sint8korr(a);
317  ll_b= mi_sint8korr(b);
318  if (piks && (flag = CMP_NUM(ll_a,ll_b)))
319  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
320  a= end;
321  b+= 8;
322  break;
323  }
324  case HA_KEYTYPE_ULONGLONG:
325  {
326  uint64_t ll_a,ll_b;
327  ll_a= mi_uint8korr(a);
328  ll_b= mi_uint8korr(b);
329  if (piks && (flag = CMP_NUM(ll_a,ll_b)))
330  return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
331  a= end;
332  b+= 8;
333  break;
334  }
335  case HA_KEYTYPE_END: /* Ready */
336  goto end; /* diff_pos is incremented */
337  }
338  }
339  (*diff_pos)++;
340 end:
341  if (!(nextflag & SEARCH_FIND))
342  {
343  uint32_t i;
344  if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
345  return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
346  flag=0;
347  for (i=keyseg->length ; i-- > 0 ; )
348  {
349  if (*a++ != *b++)
350  {
351  flag= FCMP(a[-1],b[-1]);
352  break;
353  }
354  }
355  if (nextflag & SEARCH_SAME)
356  return (flag); /* read same */
357  if (nextflag & SEARCH_BIGGER)
358  return (flag <= 0 ? -1 : 1); /* read next */
359  return (flag < 0 ? -1 : 1); /* read previous */
360  }
361  return 0;
362 } /* ha_key_cmp */
363 
364 
365 /*
366  Find the first NULL value in index-suffix values tuple
367 
368  SYNOPSIS
369  ha_find_null()
370  keyseg Array of keyparts for key suffix
371  a Key suffix value tuple
372 
373  DESCRIPTION
374  Find the first NULL value in index-suffix values tuple.
375 
376  TODO
377  Consider optimizing this function or its use so we don't search for
378  NULL values in completely NOT NULL index suffixes.
379 
380  RETURN
381  First key part that has NULL as value in values tuple, or the last key
382  part (with keyseg->type==HA_TYPE_END) if values tuple doesn't contain
383  NULLs.
384 */
385 
386 HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, unsigned char *a)
387 {
388  for (; (enum ha_base_keytype) keyseg->type != HA_KEYTYPE_END; keyseg++)
389  {
390  unsigned char *end;
391  if (keyseg->null_bit)
392  {
393  if (!*a++)
394  return keyseg;
395  }
396  end= a+ keyseg->length;
397 
398  switch ((enum ha_base_keytype) keyseg->type) {
399  case HA_KEYTYPE_TEXT:
400  case HA_KEYTYPE_BINARY:
401  if (keyseg->flag & HA_SPACE_PACK)
402  {
403  int a_length;
404  get_key_length(a_length, a);
405  a += a_length;
406  break;
407  }
408  else
409  a= end;
410  break;
411  case HA_KEYTYPE_VARTEXT1:
412  case HA_KEYTYPE_VARTEXT2:
413  case HA_KEYTYPE_VARBINARY1:
414  case HA_KEYTYPE_VARBINARY2:
415  {
416  int a_length;
417  get_key_length(a_length, a);
418  a+= a_length;
419  break;
420  }
421  case HA_KEYTYPE_LONG_INT:
422  case HA_KEYTYPE_ULONG_INT:
423  case HA_KEYTYPE_LONGLONG:
424  case HA_KEYTYPE_ULONGLONG:
425  case HA_KEYTYPE_DOUBLE:
426  a= end;
427  break;
428  case HA_KEYTYPE_END:
429  /* keep compiler happy */
430  assert(0);
431  break;
432  }
433  }
434  return keyseg;
435 }
436 
437 
438 
TODO: Rename this file - func.h is stupid.