Drizzled Public API Documentation

my_handler.cc

00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00020 #include <config.h>
00021 
00022 #include <drizzled/charset_info.h>
00023 #include <drizzled/base.h>
00024 #include <plugin/myisam/my_handler.h>
00025 #include <drizzled/internal/my_sys.h>
00026 
00027 #include <cassert>
00028 #include <algorithm>
00029 
00030 using namespace drizzled;
00031 using namespace std;
00032 
00033 template<class T>
00034 int CMP_NUM(const T& a, const T&b)
00035 {
00036   return (a < b) ? -1 : (a == b) ? 0 : 1;
00037 }
00038 
00039 
00040 int ha_compare_text(const CHARSET_INFO * const charset_info, unsigned char *a, uint32_t a_length,
00041         unsigned char *b, uint32_t b_length, bool part_key,
00042         bool skip_end_space)
00043 {
00044   if (!part_key)
00045     return charset_info->coll->strnncollsp(charset_info, a, a_length,
00046                                            b, b_length, (bool)!skip_end_space);
00047   return charset_info->coll->strnncoll(charset_info, a, a_length,
00048                                        b, b_length, part_key);
00049 }
00050 
00051 
00052 static int compare_bin(unsigned char *a, uint32_t a_length, unsigned char *b, uint32_t b_length,
00053                        bool part_key, bool skip_end_space)
00054 {
00055   uint32_t length= min(a_length,b_length);
00056   unsigned char *end= a+ length;
00057   int flag;
00058 
00059   while (a < end)
00060     if ((flag= (int) *a++ - (int) *b++))
00061       return flag;
00062   if (part_key && b_length < a_length)
00063     return 0;
00064   if (skip_end_space && a_length != b_length)
00065   {
00066     int swap= 1;
00067     /*
00068       We are using space compression. We have to check if longer key
00069       has next character < ' ', in which case it's less than the shorter
00070       key that has an implicite space afterwards.
00071 
00072       This code is identical to the one in
00073       strings/ctype-simple.c:my_strnncollsp_simple
00074     */
00075     if (a_length < b_length)
00076     {
00077       /* put shorter key in a */
00078       a_length= b_length;
00079       a= b;
00080       swap= -1;         /* swap sign of result */
00081     }
00082     for (end= a + a_length-length; a < end ; a++)
00083     {
00084       if (*a != ' ')
00085   return (*a < ' ') ? -swap : swap;
00086     }
00087     return 0;
00088   }
00089   return (int) (a_length-b_length);
00090 }
00091 
00092 
00093 /*
00094   Compare two keys
00095 
00096   SYNOPSIS
00097     ha_key_cmp()
00098     keyseg  Array of key segments of key to compare
00099     a   First key to compare, in format from _mi_pack_key()
00100     This is normally key specified by user
00101     b   Second key to compare.  This is always from a row
00102     key_length  Length of key to compare.  This can be shorter than
00103     a to just compare sub keys
00104     next_flag How keys should be compared
00105     If bit SEARCH_FIND is not set the keys includes the row
00106     position and this should also be compared
00107     diff_pos    OUT Number of first keypart where values differ, counting
00108                 from one.
00109     diff_pos[1] OUT  (b + diff_pos[1]) points to first value in tuple b
00110                       that is different from corresponding value in tuple a.
00111 
00112   EXAMPLES
00113    Example1: if the function is called for tuples
00114      ('aaa','bbb') and ('eee','fff'), then
00115      diff_pos[0] = 1 (as 'aaa' != 'eee')
00116      diff_pos[1] = 0 (offset from beggining of tuple b to 'eee' keypart).
00117 
00118    Example2: if the index function is called for tuples
00119      ('aaa','bbb') and ('aaa','fff'),
00120      diff_pos[0] = 2 (as 'aaa' != 'eee')
00121      diff_pos[1] = 3 (offset from beggining of tuple b to 'fff' keypart,
00122                       here we assume that first key part is CHAR(3) NOT NULL)
00123 
00124   NOTES
00125     Number-keys can't be splited
00126 
00127   RETURN VALUES
00128     <0  If a < b
00129     0 If a == b
00130     >0  If a > b
00131 */
00132 
00133 #define FCMP(A,B) ((int) (A) - (int) (B))
00134 
00135 int ha_key_cmp(register HA_KEYSEG *keyseg, register unsigned char *a,
00136          register unsigned char *b, uint32_t key_length, uint32_t nextflag,
00137          uint32_t *diff_pos)
00138 {
00139   int flag;
00140   int32_t l_1,l_2;
00141   uint32_t u_1,u_2;
00142   double d_1,d_2;
00143   uint32_t next_key_length;
00144   unsigned char *orig_b= b;
00145 
00146   *diff_pos=0;
00147   for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++)
00148   {
00149     unsigned char *end;
00150     uint32_t piks=! (keyseg->flag & HA_NO_SORT);
00151     (*diff_pos)++;
00152     diff_pos[1]= (uint)(b - orig_b);
00153 
00154     /* Handle NULL part */
00155     if (keyseg->null_bit)
00156     {
00157       key_length--;
00158       if (*a != *b && piks)
00159       {
00160         flag = (int) *a - (int) *b;
00161         return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
00162       }
00163       b++;
00164       if (!*a++)                                /* If key was NULL */
00165       {
00166         if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
00167           nextflag=SEARCH_SAME;                 /* Allow duplicate keys */
00168     else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL)
00169   {
00170     /*
00171       This is only used from mi_check() to calculate cardinality.
00172       It can't be used when searching for a key as this would cause
00173       compare of (a,b) and (b,a) to return the same value.
00174     */
00175     return -1;
00176   }
00177         next_key_length=key_length;
00178         continue;                               /* To next key part */
00179       }
00180     }
00181     end= a+ min((uint32_t)keyseg->length,key_length);
00182     next_key_length=key_length-keyseg->length;
00183 
00184     switch ((enum ha_base_keytype) keyseg->type) {
00185     case HA_KEYTYPE_TEXT:                       /* Ascii; Key is converted */
00186       if (keyseg->flag & HA_SPACE_PACK)
00187       {
00188         int a_length,b_length,pack_length;
00189         get_key_length(a_length,a);
00190         get_key_pack_length(b_length,pack_length,b);
00191         next_key_length=key_length-b_length-pack_length;
00192 
00193         if (piks &&
00194             (flag=ha_compare_text(keyseg->charset,a,a_length,b,b_length,
00195           (bool) ((nextflag & SEARCH_PREFIX) &&
00196                next_key_length <= 0),
00197           (bool)!(nextflag & SEARCH_PREFIX))))
00198           return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
00199         a+=a_length;
00200         b+=b_length;
00201         break;
00202       }
00203       else
00204       {
00205   uint32_t length=(uint) (end-a), a_length=length, b_length=length;
00206         if (piks &&
00207             (flag= ha_compare_text(keyseg->charset, a, a_length, b, b_length,
00208            (bool) ((nextflag & SEARCH_PREFIX) &&
00209                 next_key_length <= 0),
00210            (bool)!(nextflag & SEARCH_PREFIX))))
00211           return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
00212         a=end;
00213         b+=length;
00214       }
00215       break;
00216     case HA_KEYTYPE_BINARY:
00217       if (keyseg->flag & HA_SPACE_PACK)
00218       {
00219         int a_length,b_length,pack_length;
00220         get_key_length(a_length,a);
00221         get_key_pack_length(b_length,pack_length,b);
00222         next_key_length=key_length-b_length-pack_length;
00223 
00224         if (piks &&
00225       (flag=compare_bin(a,a_length,b,b_length,
00226                               (bool) ((nextflag & SEARCH_PREFIX) &&
00227                                          next_key_length <= 0),1)))
00228           return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
00229         a+=a_length;
00230         b+=b_length;
00231         break;
00232       }
00233       else
00234       {
00235         uint32_t length=keyseg->length;
00236         if (piks &&
00237       (flag=compare_bin(a,length,b,length,
00238                               (bool) ((nextflag & SEARCH_PREFIX) &&
00239                                          next_key_length <= 0),0)))
00240           return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
00241         a+=length;
00242         b+=length;
00243       }
00244       break;
00245     case HA_KEYTYPE_VARTEXT1:
00246     case HA_KEYTYPE_VARTEXT2:
00247       {
00248         int a_length,b_length,pack_length;
00249         get_key_length(a_length,a);
00250         get_key_pack_length(b_length,pack_length,b);
00251         next_key_length=key_length-b_length-pack_length;
00252 
00253         if (piks &&
00254       (flag= ha_compare_text(keyseg->charset,a,a_length,b,b_length,
00255                                    (bool) ((nextflag & SEARCH_PREFIX) &&
00256                                               next_key_length <= 0),
00257            (bool) ((nextflag & (SEARCH_FIND |
00258                  SEARCH_UPDATE)) ==
00259                 SEARCH_FIND &&
00260                                               ! (keyseg->flag &
00261                                                  HA_END_SPACE_ARE_EQUAL)))))
00262           return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
00263         a+= a_length;
00264         b+= b_length;
00265         break;
00266       }
00267     case HA_KEYTYPE_VARBINARY1:
00268     case HA_KEYTYPE_VARBINARY2:
00269       {
00270         int a_length,b_length,pack_length;
00271         get_key_length(a_length,a);
00272         get_key_pack_length(b_length,pack_length,b);
00273         next_key_length=key_length-b_length-pack_length;
00274 
00275         if (piks &&
00276       (flag=compare_bin(a,a_length,b,b_length,
00277                               (bool) ((nextflag & SEARCH_PREFIX) &&
00278                                          next_key_length <= 0), 0)))
00279           return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
00280         a+=a_length;
00281         b+=b_length;
00282         break;
00283       }
00284     case HA_KEYTYPE_LONG_INT:
00285       l_1= mi_sint4korr(a);
00286       l_2= mi_sint4korr(b);
00287       if (piks && (flag = CMP_NUM(l_1,l_2)))
00288         return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
00289       a=  end;
00290       b+= 4; /* sizeof(long int); */
00291       break;
00292     case HA_KEYTYPE_ULONG_INT:
00293       u_1= mi_sint4korr(a);
00294       u_2= mi_sint4korr(b);
00295       if (piks && (flag = CMP_NUM(u_1,u_2)))
00296         return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
00297       a=  end;
00298       b+= 4; /* sizeof(long int); */
00299       break;
00300     case HA_KEYTYPE_DOUBLE:
00301       mi_float8get(d_1,a);
00302       mi_float8get(d_2,b);
00303       /*
00304         The following may give a compiler warning about floating point
00305         comparison not being safe, but this is ok in this context as
00306         we are bascily doing sorting
00307       */
00308       if (piks && (flag = CMP_NUM(d_1,d_2)))
00309         return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
00310       a=  end;
00311       b+= 8;  /* sizeof(double); */
00312       break;
00313     case HA_KEYTYPE_LONGLONG:
00314     {
00315       int64_t ll_a,ll_b;
00316       ll_a= mi_sint8korr(a);
00317       ll_b= mi_sint8korr(b);
00318       if (piks && (flag = CMP_NUM(ll_a,ll_b)))
00319         return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
00320       a=  end;
00321       b+= 8;
00322       break;
00323     }
00324     case HA_KEYTYPE_ULONGLONG:
00325     {
00326       uint64_t ll_a,ll_b;
00327       ll_a= mi_uint8korr(a);
00328       ll_b= mi_uint8korr(b);
00329       if (piks && (flag = CMP_NUM(ll_a,ll_b)))
00330         return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
00331       a=  end;
00332       b+= 8;
00333       break;
00334     }
00335     case HA_KEYTYPE_END:                        /* Ready */
00336       goto end;                                 /* diff_pos is incremented */
00337     }
00338   }
00339   (*diff_pos)++;
00340 end:
00341   if (!(nextflag & SEARCH_FIND))
00342   {
00343     uint32_t i;
00344     if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
00345       return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
00346     flag=0;
00347     for (i=keyseg->length ; i-- > 0 ; )
00348     {
00349       if (*a++ != *b++)
00350       {
00351         flag= FCMP(a[-1],b[-1]);
00352         break;
00353       }
00354     }
00355     if (nextflag & SEARCH_SAME)
00356       return (flag);                            /* read same */
00357     if (nextflag & SEARCH_BIGGER)
00358       return (flag <= 0 ? -1 : 1);              /* read next */
00359     return (flag < 0 ? -1 : 1);                 /* read previous */
00360   }
00361   return 0;
00362 } /* ha_key_cmp */
00363 
00364 
00365 /*
00366   Find the first NULL value in index-suffix values tuple
00367 
00368   SYNOPSIS
00369     ha_find_null()
00370       keyseg     Array of keyparts for key suffix
00371       a          Key suffix value tuple
00372 
00373   DESCRIPTION
00374     Find the first NULL value in index-suffix values tuple.
00375 
00376   TODO
00377     Consider optimizing this function or its use so we don't search for
00378     NULL values in completely NOT NULL index suffixes.
00379 
00380   RETURN
00381     First key part that has NULL as value in values tuple, or the last key
00382     part (with keyseg->type==HA_TYPE_END) if values tuple doesn't contain
00383     NULLs.
00384 */
00385 
00386 HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, unsigned char *a)
00387 {
00388   for (; (enum ha_base_keytype) keyseg->type != HA_KEYTYPE_END; keyseg++)
00389   {
00390     unsigned char *end;
00391     if (keyseg->null_bit)
00392     {
00393       if (!*a++)
00394         return keyseg;
00395     }
00396     end= a+ keyseg->length;
00397 
00398     switch ((enum ha_base_keytype) keyseg->type) {
00399     case HA_KEYTYPE_TEXT:
00400     case HA_KEYTYPE_BINARY:
00401       if (keyseg->flag & HA_SPACE_PACK)
00402       {
00403         int a_length;
00404         get_key_length(a_length, a);
00405         a += a_length;
00406         break;
00407       }
00408       else
00409         a= end;
00410       break;
00411     case HA_KEYTYPE_VARTEXT1:
00412     case HA_KEYTYPE_VARTEXT2:
00413     case HA_KEYTYPE_VARBINARY1:
00414     case HA_KEYTYPE_VARBINARY2:
00415       {
00416         int a_length;
00417         get_key_length(a_length, a);
00418         a+= a_length;
00419         break;
00420       }
00421     case HA_KEYTYPE_LONG_INT:
00422     case HA_KEYTYPE_ULONG_INT:
00423     case HA_KEYTYPE_LONGLONG:
00424     case HA_KEYTYPE_ULONGLONG:
00425     case HA_KEYTYPE_DOUBLE:
00426       a= end;
00427       break;
00428     case HA_KEYTYPE_END:
00429       /* keep compiler happy */
00430       assert(0);
00431       break;
00432     }
00433   }
00434   return keyseg;
00435 }
00436 
00437 
00438