mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 14:33:32 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			454 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			454 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
 | 
						|
   
 | 
						|
   This library is free software; you can redistribute it and/or
 | 
						|
   modify it under the terms of the GNU Library General Public
 | 
						|
   License as published by the Free Software Foundation; either
 | 
						|
   version 2 of the License, or (at your option) any later version.
 | 
						|
   
 | 
						|
   This library is distributed in the hope that it will be useful,
 | 
						|
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
   Library General Public License for more details.
 | 
						|
 | 
						|
   You should have received a copy of the GNU Library General Public
 | 
						|
   License along with this library; if not, write to the Free
 | 
						|
   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 | 
						|
   MA 02111-1307, USA */
 | 
						|
 | 
						|
#include "my_handler.h"
 | 
						|
 | 
						|
int mi_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
 | 
						|
		    uchar *b, uint b_length, my_bool part_key,
 | 
						|
		    my_bool skip_end_space)
 | 
						|
{
 | 
						|
  if (!part_key)
 | 
						|
    return charset_info->coll->strnncollsp(charset_info, a, a_length,
 | 
						|
                                           b, b_length, !skip_end_space);
 | 
						|
  return charset_info->coll->strnncoll(charset_info, a, a_length,
 | 
						|
                                       b, b_length, part_key);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
 | 
						|
                       my_bool part_key, my_bool skip_end_space)
 | 
						|
{
 | 
						|
  uint length= min(a_length,b_length);
 | 
						|
  uchar *end= a+ length;
 | 
						|
  int flag;
 | 
						|
 | 
						|
  while (a < end)
 | 
						|
    if ((flag= (int) *a++ - (int) *b++))
 | 
						|
      return flag;
 | 
						|
  if (part_key && b_length < a_length)
 | 
						|
    return 0;
 | 
						|
  if (skip_end_space && a_length != b_length)
 | 
						|
  {
 | 
						|
    int swap= 1;
 | 
						|
    /*
 | 
						|
      We are using space compression. We have to check if longer key
 | 
						|
      has next character < ' ', in which case it's less than the shorter
 | 
						|
      key that has an implicite space afterwards.
 | 
						|
 | 
						|
      This code is identical to the one in
 | 
						|
      strings/ctype-simple.c:my_strnncollsp_simple
 | 
						|
    */
 | 
						|
    if (a_length < b_length)
 | 
						|
    {
 | 
						|
      /* put shorter key in a */
 | 
						|
      a_length= b_length;
 | 
						|
      a= b;
 | 
						|
      swap= -1;					/* swap sign of result */
 | 
						|
    }
 | 
						|
    for (end= a + a_length-length; a < end ; a++)
 | 
						|
    {
 | 
						|
      if (*a != ' ')
 | 
						|
	return (*a < ' ') ? -swap : swap;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
  return (int) (a_length-b_length);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Compare two keys
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    ha_key_cmp()
 | 
						|
    keyseg	Key segments of key to compare
 | 
						|
    a		First key to compare, in format from _mi_pack_key()
 | 
						|
		This is normally key specified by user
 | 
						|
    b		Second key to compare.  This is always from a row
 | 
						|
    key_length	Length of key to compare.  This can be shorter than
 | 
						|
		a to just compare sub keys
 | 
						|
    next_flag	How keys should be compared
 | 
						|
		If bit SEARCH_FIND is not set the keys includes the row
 | 
						|
		position and this should also be compared
 | 
						|
 | 
						|
  NOTES
 | 
						|
    Number-keys can't be splited
 | 
						|
  
 | 
						|
  RETURN VALUES
 | 
						|
    <0	If a < b
 | 
						|
    0	If a == b
 | 
						|
    >0	If a > b
 | 
						|
*/
 | 
						|
 | 
						|
#define FCMP(A,B) ((int) (A) - (int) (B))
 | 
						|
 | 
						|
int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
 | 
						|
	       register uchar *b, uint key_length, uint nextflag,
 | 
						|
	       uint *diff_pos)
 | 
						|
{
 | 
						|
  int flag;
 | 
						|
  int16 s_1,s_2;
 | 
						|
  int32 l_1,l_2;
 | 
						|
  uint32 u_1,u_2;
 | 
						|
  float f_1,f_2;
 | 
						|
  double d_1,d_2;
 | 
						|
  uint next_key_length;
 | 
						|
 | 
						|
  *diff_pos=0;
 | 
						|
  for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++)
 | 
						|
  {
 | 
						|
    uchar *end;
 | 
						|
    uint piks=! (keyseg->flag & HA_NO_SORT);
 | 
						|
    (*diff_pos)++;
 | 
						|
 | 
						|
    /* Handle NULL part */
 | 
						|
    if (keyseg->null_bit)
 | 
						|
    {
 | 
						|
      key_length--;
 | 
						|
      if (*a != *b && piks)
 | 
						|
      {
 | 
						|
        flag = (int) *a - (int) *b;
 | 
						|
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
      }
 | 
						|
      b++;
 | 
						|
      if (!*a++)                                /* If key was NULL */
 | 
						|
      {
 | 
						|
        if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
 | 
						|
          nextflag=SEARCH_SAME;                 /* Allow duplicate keys */
 | 
						|
  	else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL)
 | 
						|
	{
 | 
						|
	  /*
 | 
						|
	    This is only used from mi_check() to calculate cardinality.
 | 
						|
	    It can't be used when searching for a key as this would cause
 | 
						|
	    compare of (a,b) and (b,a) to return the same value.
 | 
						|
	  */
 | 
						|
	  return -1;
 | 
						|
	}
 | 
						|
        next_key_length=key_length;
 | 
						|
        continue;                               /* To next key part */
 | 
						|
      }
 | 
						|
    }
 | 
						|
    end= a+ min(keyseg->length,key_length);
 | 
						|
    next_key_length=key_length-keyseg->length;
 | 
						|
 | 
						|
    switch ((enum ha_base_keytype) keyseg->type) {
 | 
						|
    case HA_KEYTYPE_TEXT:                       /* Ascii; Key is converted */
 | 
						|
      if (keyseg->flag & HA_SPACE_PACK)
 | 
						|
      {
 | 
						|
        int a_length,b_length,pack_length;
 | 
						|
        get_key_length(a_length,a);
 | 
						|
        get_key_pack_length(b_length,pack_length,b);
 | 
						|
        next_key_length=key_length-b_length-pack_length;
 | 
						|
 | 
						|
        if (piks &&
 | 
						|
            (flag=mi_compare_text(keyseg->charset,a,a_length,b,b_length,
 | 
						|
				  (my_bool) ((nextflag & SEARCH_PREFIX) &&
 | 
						|
					     next_key_length <= 0),
 | 
						|
				  (my_bool)!(nextflag & SEARCH_PREFIX))))
 | 
						|
          return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
        a+=a_length;
 | 
						|
        b+=b_length;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
	uint length=(uint) (end-a), a_length=length, b_length=length;
 | 
						|
        if (piks &&
 | 
						|
            (flag= mi_compare_text(keyseg->charset, a, a_length, b, b_length,
 | 
						|
				   (my_bool) ((nextflag & SEARCH_PREFIX) &&
 | 
						|
					      next_key_length <= 0),
 | 
						|
				   (my_bool)!(nextflag & SEARCH_PREFIX))))
 | 
						|
          return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
        a=end;
 | 
						|
        b+=length;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case HA_KEYTYPE_BINARY:
 | 
						|
    case HA_KEYTYPE_BIT:
 | 
						|
      if (keyseg->flag & HA_SPACE_PACK)
 | 
						|
      {
 | 
						|
        int a_length,b_length,pack_length;
 | 
						|
        get_key_length(a_length,a);
 | 
						|
        get_key_pack_length(b_length,pack_length,b);
 | 
						|
        next_key_length=key_length-b_length-pack_length;
 | 
						|
 | 
						|
        if (piks &&
 | 
						|
	    (flag=compare_bin(a,a_length,b,b_length,
 | 
						|
                              (my_bool) ((nextflag & SEARCH_PREFIX) &&
 | 
						|
                                         next_key_length <= 0),1)))
 | 
						|
          return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
        a+=a_length;
 | 
						|
        b+=b_length;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        uint length=keyseg->length;
 | 
						|
        if (piks &&
 | 
						|
	    (flag=compare_bin(a,length,b,length,
 | 
						|
                              (my_bool) ((nextflag & SEARCH_PREFIX) &&
 | 
						|
                                         next_key_length <= 0),0)))
 | 
						|
          return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
        a+=length;
 | 
						|
        b+=length;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case HA_KEYTYPE_VARTEXT1:
 | 
						|
    case HA_KEYTYPE_VARTEXT2:
 | 
						|
      {
 | 
						|
        int a_length,b_length,pack_length;
 | 
						|
        get_key_length(a_length,a);
 | 
						|
        get_key_pack_length(b_length,pack_length,b);
 | 
						|
        next_key_length=key_length-b_length-pack_length;
 | 
						|
 | 
						|
        if (piks &&
 | 
						|
	    (flag= mi_compare_text(keyseg->charset,a,a_length,b,b_length,
 | 
						|
                                   (my_bool) ((nextflag & SEARCH_PREFIX) &&
 | 
						|
                                              next_key_length <= 0),
 | 
						|
				   (my_bool) ((nextflag & (SEARCH_FIND |
 | 
						|
							   SEARCH_UPDATE)) ==
 | 
						|
					      SEARCH_FIND &&
 | 
						|
                                              ! (keyseg->flag &
 | 
						|
                                                 HA_END_SPACE_ARE_EQUAL)))))
 | 
						|
          return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
        a+= a_length;
 | 
						|
        b+= b_length;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case HA_KEYTYPE_VARBINARY1:
 | 
						|
    case HA_KEYTYPE_VARBINARY2:
 | 
						|
      {
 | 
						|
        int a_length,b_length,pack_length;
 | 
						|
        get_key_length(a_length,a);
 | 
						|
        get_key_pack_length(b_length,pack_length,b);
 | 
						|
        next_key_length=key_length-b_length-pack_length;
 | 
						|
 | 
						|
        if (piks &&
 | 
						|
	    (flag=compare_bin(a,a_length,b,b_length,
 | 
						|
                              (my_bool) ((nextflag & SEARCH_PREFIX) &&
 | 
						|
                                         next_key_length <= 0), 0)))
 | 
						|
          return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
        a+=a_length;
 | 
						|
        b+=b_length;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case HA_KEYTYPE_INT8:
 | 
						|
    {
 | 
						|
      int i_1= (int) *((signed char*) a);
 | 
						|
      int i_2= (int) *((signed char*) b);
 | 
						|
      if (piks && (flag = CMP_NUM(i_1,i_2)))
 | 
						|
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
      a= end;
 | 
						|
      b++;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case HA_KEYTYPE_SHORT_INT:
 | 
						|
      s_1= mi_sint2korr(a);
 | 
						|
      s_2= mi_sint2korr(b);
 | 
						|
      if (piks && (flag = CMP_NUM(s_1,s_2)))
 | 
						|
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
      a=  end;
 | 
						|
      b+= 2; /* sizeof(short int); */
 | 
						|
      break;
 | 
						|
    case HA_KEYTYPE_USHORT_INT:
 | 
						|
      {
 | 
						|
        uint16 us_1,us_2;
 | 
						|
        us_1= mi_sint2korr(a);
 | 
						|
        us_2= mi_sint2korr(b);
 | 
						|
        if (piks && (flag = CMP_NUM(us_1,us_2)))
 | 
						|
          return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
        a=  end;
 | 
						|
        b+=2; /* sizeof(short int); */
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    case HA_KEYTYPE_LONG_INT:
 | 
						|
      l_1= mi_sint4korr(a);
 | 
						|
      l_2= mi_sint4korr(b);
 | 
						|
      if (piks && (flag = CMP_NUM(l_1,l_2)))
 | 
						|
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
      a=  end;
 | 
						|
      b+= 4; /* sizeof(long int); */
 | 
						|
      break;
 | 
						|
    case HA_KEYTYPE_ULONG_INT:
 | 
						|
      u_1= mi_sint4korr(a);
 | 
						|
      u_2= mi_sint4korr(b);
 | 
						|
      if (piks && (flag = CMP_NUM(u_1,u_2)))
 | 
						|
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
      a=  end;
 | 
						|
      b+= 4; /* sizeof(long int); */
 | 
						|
      break;
 | 
						|
    case HA_KEYTYPE_INT24:
 | 
						|
      l_1=mi_sint3korr(a);
 | 
						|
      l_2=mi_sint3korr(b);
 | 
						|
      if (piks && (flag = CMP_NUM(l_1,l_2)))
 | 
						|
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
      a=  end;
 | 
						|
      b+= 3;
 | 
						|
      break;
 | 
						|
    case HA_KEYTYPE_UINT24:
 | 
						|
      l_1=mi_uint3korr(a);
 | 
						|
      l_2=mi_uint3korr(b);
 | 
						|
      if (piks && (flag = CMP_NUM(l_1,l_2)))
 | 
						|
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
      a=  end;
 | 
						|
      b+= 3;
 | 
						|
      break;
 | 
						|
    case HA_KEYTYPE_FLOAT:
 | 
						|
      mi_float4get(f_1,a);
 | 
						|
      mi_float4get(f_2,b);
 | 
						|
      /*
 | 
						|
        The following may give a compiler warning about floating point
 | 
						|
        comparison not being safe, but this is ok in this context as
 | 
						|
        we are bascily doing sorting
 | 
						|
      */
 | 
						|
      if (piks && (flag = CMP_NUM(f_1,f_2)))
 | 
						|
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
      a=  end;
 | 
						|
      b+= 4; /* sizeof(float); */
 | 
						|
      break;
 | 
						|
    case HA_KEYTYPE_DOUBLE:
 | 
						|
      mi_float8get(d_1,a);
 | 
						|
      mi_float8get(d_2,b);
 | 
						|
      /*
 | 
						|
        The following may give a compiler warning about floating point
 | 
						|
        comparison not being safe, but this is ok in this context as
 | 
						|
        we are bascily doing sorting
 | 
						|
      */
 | 
						|
      if (piks && (flag = CMP_NUM(d_1,d_2)))
 | 
						|
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
      a=  end;
 | 
						|
      b+= 8;  /* sizeof(double); */
 | 
						|
      break;
 | 
						|
    case HA_KEYTYPE_NUM:                                /* Numeric key */
 | 
						|
    {
 | 
						|
      int swap_flag= 0;
 | 
						|
      int alength,blength;
 | 
						|
 | 
						|
      if (keyseg->flag & HA_REVERSE_SORT)
 | 
						|
      {
 | 
						|
        swap_variables(uchar*, a, b);
 | 
						|
        swap_flag=1;                            /* Remember swap of a & b */
 | 
						|
        end= a+ (int) (end-b);
 | 
						|
      }
 | 
						|
      if (keyseg->flag & HA_SPACE_PACK)
 | 
						|
      {
 | 
						|
        alength= *a++; blength= *b++;
 | 
						|
        end=a+alength;
 | 
						|
        next_key_length=key_length-blength-1;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        alength= (int) (end-a);
 | 
						|
        blength=keyseg->length;
 | 
						|
        /* remove pre space from keys */
 | 
						|
        for ( ; alength && *a == ' ' ; a++, alength--) ;
 | 
						|
        for ( ; blength && *b == ' ' ; b++, blength--) ;
 | 
						|
      }
 | 
						|
      if (piks)
 | 
						|
      {
 | 
						|
	if (*a == '-')
 | 
						|
	{
 | 
						|
	  if (*b != '-')
 | 
						|
	    return -1;
 | 
						|
	  a++; b++;
 | 
						|
	  swap_variables(uchar*, a, b);
 | 
						|
	  swap_variables(int, alength, blength);
 | 
						|
	  swap_flag=1-swap_flag;
 | 
						|
	  alength--; blength--;
 | 
						|
	  end=a+alength;
 | 
						|
	}
 | 
						|
	else if (*b == '-')
 | 
						|
	  return 1;
 | 
						|
	while (alength && (*a == '+' || *a == '0'))
 | 
						|
	{
 | 
						|
	  a++; alength--;
 | 
						|
	}
 | 
						|
	while (blength && (*b == '+' || *b == '0'))
 | 
						|
	{
 | 
						|
	  b++; blength--;
 | 
						|
	}
 | 
						|
	if (alength != blength)
 | 
						|
	  return (alength < blength) ? -1 : 1;
 | 
						|
	while (a < end)
 | 
						|
	  if (*a++ !=  *b++)
 | 
						|
	    return ((int) a[-1] - (int) b[-1]);
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        b+=(end-a);
 | 
						|
        a=end;
 | 
						|
      }
 | 
						|
 | 
						|
      if (swap_flag)                            /* Restore pointers */
 | 
						|
        swap_variables(uchar*, a, b);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
#ifdef HAVE_LONG_LONG
 | 
						|
    case HA_KEYTYPE_LONGLONG:
 | 
						|
    {
 | 
						|
      longlong ll_a,ll_b;
 | 
						|
      ll_a= mi_sint8korr(a);
 | 
						|
      ll_b= mi_sint8korr(b);
 | 
						|
      if (piks && (flag = CMP_NUM(ll_a,ll_b)))
 | 
						|
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
      a=  end;
 | 
						|
      b+= 8;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case HA_KEYTYPE_ULONGLONG:
 | 
						|
    {
 | 
						|
      ulonglong ll_a,ll_b;
 | 
						|
      ll_a= mi_uint8korr(a);
 | 
						|
      ll_b= mi_uint8korr(b);
 | 
						|
      if (piks && (flag = CMP_NUM(ll_a,ll_b)))
 | 
						|
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 | 
						|
      a=  end;
 | 
						|
      b+= 8;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    case HA_KEYTYPE_END:                        /* Ready */
 | 
						|
      goto end;                                 /* diff_pos is incremented */
 | 
						|
    }
 | 
						|
  }
 | 
						|
  (*diff_pos)++;
 | 
						|
end:
 | 
						|
  if (!(nextflag & SEARCH_FIND))
 | 
						|
  {
 | 
						|
    uint i;
 | 
						|
    if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
 | 
						|
      return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
 | 
						|
    flag=0;
 | 
						|
    for (i=keyseg->length ; i-- > 0 ; )
 | 
						|
    {
 | 
						|
      if (*a++ != *b++)
 | 
						|
      {
 | 
						|
        flag= FCMP(a[-1],b[-1]);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (nextflag & SEARCH_SAME)
 | 
						|
      return (flag);                            /* read same */
 | 
						|
    if (nextflag & SEARCH_BIGGER)
 | 
						|
      return (flag <= 0 ? -1 : 1);              /* read next */
 | 
						|
    return (flag < 0 ? -1 : 1);                 /* read previous */
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
} /* ha_key_cmp */
 |