_search.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:25k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  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; either version 2 of the License, or
  6.    (at your option) any later version.
  7.    
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16. /* S|ker efter positionen f|r en nyckel samt d{rmedh|rande funktioner */
  17. #include "isamdef.h"
  18. #include "m_ctype.h"
  19. #define CMP(a,b) (a<b ? -1 : a == b ? 0 : 1)
  20. /* Check index */
  21. int _nisam_check_index(N_INFO *info, int inx)
  22. {
  23.   if (inx == -1) /* Use last index */
  24.     inx=info->lastinx;
  25.   if (inx >= (int) info->s->state.keys || inx < 0)
  26.   {
  27.     my_errno=HA_ERR_WRONG_INDEX;
  28.     return -1;
  29.   }
  30.   if (info->lastinx != inx) /* Index changed */
  31.   {
  32.     info->lastinx = inx;
  33.     info->lastpos = NI_POS_ERROR;
  34.     info->update= ((info->update & (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED)) |
  35.    HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND);
  36.   }
  37.   if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
  38.     return(-1);
  39.   return(inx);
  40. } /* ni_check_index */
  41. /* S|ker reda p} positionen f|r ett record p} basen av en nyckel */
  42. /* Positionen l{ggs i info->lastpos */
  43. /* Returns -1 if not found and 1 if search at upper levels */
  44. int _nisam_search(register N_INFO *info, register N_KEYDEF *keyinfo, uchar *key, uint key_len, uint nextflag, register ulong pos)
  45. {
  46.   int error,flag;
  47.   uint nod_flag;
  48.   uchar *keypos,*maxpos;
  49.   uchar lastkey[N_MAX_KEY_BUFF],*buff;
  50.   DBUG_ENTER("_nisam_search");
  51.   DBUG_PRINT("enter",("pos: %ld  nextflag: %d  lastpos: %ld",
  52.       pos,nextflag,info->lastpos));
  53.   if (pos == NI_POS_ERROR)
  54.   {
  55.     my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
  56.     info->lastpos= NI_POS_ERROR;
  57.     if (!(nextflag & (SEARCH_SMALLER | SEARCH_BIGGER | SEARCH_LAST)))
  58.       DBUG_RETURN(-1); /* Not found ; return error */
  59.     DBUG_RETURN(1); /* Search at upper levels */
  60.   }
  61.   if (!(buff=_nisam_fetch_keypage(info,keyinfo,pos,info->buff,
  62.        test(!(nextflag & SEARCH_SAVE_BUFF)))))
  63.     goto err;
  64.   DBUG_DUMP("page",(byte*) buff,getint(buff));
  65.   flag=(*keyinfo->bin_search)(info,keyinfo,buff,key,key_len,nextflag,
  66.       &keypos,lastkey);
  67.   nod_flag=test_if_nod(buff);
  68.   maxpos=buff+getint(buff)-1;
  69.   if (flag)
  70.   {
  71.     if ((error=_nisam_search(info,keyinfo,key,key_len,nextflag,
  72.   _nisam_kpos(nod_flag,keypos))) <= 0)
  73.       DBUG_RETURN(error);
  74.     if (flag >0)
  75.     {
  76.       if ((nextflag & (SEARCH_SMALLER | SEARCH_LAST)) &&
  77.   keypos == buff+2+nod_flag)
  78. DBUG_RETURN(1); /* Bigger than key */
  79.     }
  80.     else if (nextflag & SEARCH_BIGGER && keypos >= maxpos)
  81.       DBUG_RETURN(1); /* Smaller than key */
  82.   }
  83.   else
  84.   {
  85.     if (nextflag & SEARCH_FIND && (!(keyinfo->base.flag & HA_NOSAME)
  86.    || key_len) && nod_flag)
  87.     {
  88.       if ((error=_nisam_search(info,keyinfo,key,key_len,SEARCH_FIND,
  89.     _nisam_kpos(nod_flag,keypos))) >= 0 ||
  90.   my_errno != HA_ERR_KEY_NOT_FOUND)
  91. DBUG_RETURN(error);
  92.       info->int_pos= NI_POS_ERROR; /* Buffer not in memory */
  93.     }
  94.   }
  95.   if (pos != info->int_pos)
  96.   {
  97.     uchar *old_buff=buff;
  98.     if (!(buff=_nisam_fetch_keypage(info,keyinfo,pos,info->buff,
  99.  test(!(nextflag & SEARCH_SAVE_BUFF)))))
  100.       goto err;
  101.     keypos=buff+(keypos-old_buff);
  102.     maxpos=buff+(maxpos-old_buff);
  103.   }
  104.   if ((nextflag & (SEARCH_SMALLER | SEARCH_LAST)) && flag != 0)
  105.   {
  106.     keypos=_nisam_get_last_key(info,keyinfo,buff,lastkey,keypos);
  107.     if ((nextflag & SEARCH_LAST) &&
  108. _nisam_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND))
  109.     {
  110.       my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
  111.       goto err;
  112.     }
  113.   }
  114.   VOID((*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey));
  115.   VOID(_nisam_move_key(keyinfo,info->lastkey,lastkey));
  116.   info->lastpos=_nisam_dpos(info,nod_flag,keypos);
  117.   info->int_keypos=info->buff+ (keypos-buff);
  118.   info->int_maxpos=info->buff+ (maxpos-buff);
  119.   info->page_changed=0;
  120.   info->buff_used= (info->buff != buff);
  121.   info->last_search_keypage=info->int_pos;
  122.   DBUG_PRINT("exit",("found key at %ld",info->lastpos));
  123.   DBUG_RETURN(0);
  124. err:
  125.   DBUG_PRINT("exit",("Error: %d",my_errno));
  126.   info->lastpos= NI_POS_ERROR;
  127.   DBUG_RETURN (-1);
  128. } /* _nisam_search */
  129. /* Search after key in page-block */
  130. /* If packed key puts smaller or identical key in buff */
  131. /* ret_pos point to where find or bigger key starts */
  132. /* ARGSUSED */
  133. int _nisam_bin_search(N_INFO *info, register N_KEYDEF *keyinfo, uchar *page,
  134.    uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
  135.    uchar *buff __attribute__((unused)))
  136. {
  137.   reg4 int start,mid,end;
  138.   int flag;
  139.   uint totlength,nod_flag;
  140.   DBUG_ENTER("_nisam_bin_search");
  141.   LINT_INIT(flag);
  142.   totlength=keyinfo->base.keylength+(nod_flag=test_if_nod(page));
  143.   start=0; mid=1;
  144.   end= (int) ((getint(page)-2-nod_flag)/totlength-1);
  145.   DBUG_PRINT("test",("getint: %d  end: %d",getint(page),end));
  146.   page+=2+nod_flag;
  147.   while (start != end)
  148.   {
  149.     mid= (start+end)/2;
  150.     if ((flag=_nisam_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len,
  151.   comp_flag))
  152. >= 0)
  153.       end=mid;
  154.     else
  155.       start=mid+1;
  156.   }
  157.   if (mid != start)
  158.     flag=_nisam_key_cmp(keyinfo->seg,page+(uint) start*totlength,key,key_len,
  159.      comp_flag);
  160.   if (flag < 0)
  161.     start++; /* point at next, bigger key */
  162.   *ret_pos=page+(uint) start*totlength;
  163.   DBUG_PRINT("exit",("flag: %d  keypos: %d",flag,start));
  164.   DBUG_RETURN(flag);
  165. } /* _nisam_bin_search */
  166. /* Used instead of _nisam_bin_search() when key is packed */
  167. /* Puts smaller or identical key in buff */
  168. /* Key is searched sequentially */
  169. int _nisam_seq_search(N_INFO *info, register N_KEYDEF *keyinfo, uchar *page, uchar *key, uint key_len, uint comp_flag, uchar **ret_pos, uchar *buff)
  170. {
  171.   int flag;
  172.   uint nod_flag,length;
  173.   uchar t_buff[N_MAX_KEY_BUFF],*end;
  174.   DBUG_ENTER("_nisam_seq_search");
  175.   LINT_INIT(flag); LINT_INIT(length);
  176.   end= page+getint(page);
  177.   nod_flag=test_if_nod(page);
  178.   page+=2+nod_flag;
  179.   *ret_pos=page;
  180.   while (page < end)
  181.   {
  182.     length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff);
  183.     if ((flag=_nisam_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag)) >= 0)
  184.       break;
  185. #ifdef EXTRA_DEBUG
  186.     DBUG_PRINT("loop",("page: %lx  key: '%s'  flag: %d",page,t_buff,flag));
  187. #endif
  188.     memcpy(buff,t_buff,length);
  189.     *ret_pos=page;
  190.   }
  191.   if (flag == 0)
  192.     memcpy(buff,t_buff,length); /* Result is first key */
  193.   DBUG_PRINT("exit",("flag: %d  ret_pos: %lx",flag,*ret_pos));
  194.   DBUG_RETURN(flag);
  195. } /* _nisam_seq_search */
  196. /* Get pos to a key_block */
  197. ulong _nisam_kpos(uint nod_flag, uchar *after_key)
  198. {
  199.   after_key-=nod_flag;
  200.   switch (nod_flag) {
  201.   case 3:
  202.     return uint3korr(after_key)*512L;
  203.   case 2:
  204.     return uint2korr(after_key)*512L;
  205.   case 1:
  206.     return (uint) (*after_key)*512L;
  207.   case 0: /* At leaf page */
  208.   default: /* Impossible */
  209.     return(NI_POS_ERROR);
  210.   }
  211. } /* _kpos */
  212. /* Save pos to a key_block */
  213. void _nisam_kpointer(register N_INFO *info, register uchar *buff, ulong pos)
  214. {
  215.   pos/=512L;
  216.   switch (info->s->base.key_reflength) {
  217.   case 3: int3store(buff,pos); break;
  218.   case 2: int2store(buff,(uint) pos); break;
  219.   case 1: buff[0]= (uchar) pos; break;
  220.   default: abort(); /* impossible */
  221.   }
  222. } /* _nisam_kpointer */
  223. /* Calc pos to a data-record */
  224. ulong _nisam_dpos(N_INFO *info, uint nod_flag, uchar *after_key)
  225. {
  226.   ulong pos;
  227.   after_key-=(nod_flag + info->s->rec_reflength);
  228.   switch (info->s->rec_reflength) {
  229.   case 4:
  230.     pos= (ulong) uint4korr(after_key);
  231.     break;
  232.   case 3:
  233.     pos= (ulong) uint3korr(after_key);
  234.     break;
  235.   case 2:
  236.     pos= (ulong) uint2korr(after_key);
  237.     break;
  238.   default:
  239.     pos=0L; /* Shut compiler up */
  240.   }
  241.   return (info->s->base.options &
  242.   (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
  243.     pos*info->s->base.reclength;
  244. }
  245. /* save pos to record */
  246. void _nisam_dpointer(N_INFO *info, uchar *buff, ulong pos)
  247. {
  248.   if (!(info->s->base.options &
  249. (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
  250.     pos/=info->s->base.reclength;
  251.   switch (info->s->rec_reflength) {
  252.   case 4: int4store(buff,pos); break;
  253.   case 3: int3store(buff,pos); break;
  254.   case 2: int2store(buff,(uint) pos); break;
  255.   default: abort(); /* Impossible */
  256.   }
  257. } /* _nisam_dpointer */
  258. /*
  259. ** Compare two keys with is bigger
  260. ** Returns <0, 0, >0 acording to with is bigger
  261. ** Key_length specifies length of key to use.  Number-keys can't
  262. ** be splitted
  263. ** If flag <> SEARCH_FIND compare also position
  264. */
  265. int _nisam_key_cmp(register N_KEYSEG *keyseg, register uchar *a, register uchar *b, uint key_length, uint nextflag)
  266. {
  267.   reg4 int flag,length_diff;
  268.   int16 s_1,s_2;
  269.   int32 l_1,l_2;
  270.   uint32 u_1,u_2;
  271.   float f_1,f_2;
  272.   double d_1,d_2;
  273.   reg5 uchar *end;
  274.   if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST))
  275.       || key_length == 0)
  276.     key_length=N_MAX_KEY_BUFF*2;
  277.   for ( ; (int) key_length >0 ; key_length-= (keyseg++)->base.length)
  278.   {
  279.     end= a+ min(keyseg->base.length,key_length);
  280.     switch ((enum ha_base_keytype) keyseg->base.type) {
  281.     case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
  282.     case HA_KEYTYPE_BINARY:
  283.       if (keyseg->base.flag & HA_SPACE_PACK)
  284.       {
  285. uchar *as, *bs;
  286. int length,b_length;
  287. as=a++; bs=b++;
  288. length= (length_diff= ((int) *as - (b_length= (int) *bs))) < 0 ?
  289.   (int) *as : b_length;
  290. end= a+ min(key_length,(uint) length);
  291. #ifdef USE_STRCOLL
  292.         if (use_strcoll(default_charset_info)) {
  293.           if (((enum ha_base_keytype) keyseg->base.type) == HA_KEYTYPE_BINARY)
  294.           {
  295.             while (a < end)
  296.               if ((flag= (int) *a++ - (int) *b++))
  297.                 return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  298.           }
  299.           else
  300.           {
  301.             if ((flag = my_strnncoll(default_charset_info,
  302.      a, (int) (end-a), b, b_length)))
  303.               return (keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag;
  304.             b+= (uint) (end-a);
  305.             a=end;
  306.           }
  307.         }
  308.         else
  309. #endif
  310. {
  311.           while (a < end)
  312.             if ((flag= (int) *a++ - (int) *b++))
  313.               return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  314. }
  315. if (key_length < (uint) keyseg->base.length)
  316. { /* key_part */
  317.   if (length_diff)
  318.   {
  319.     if (length_diff < 0 || (uint) *as <= key_length)
  320.       return ((keyseg->base.flag & HA_REVERSE_SORT) ?
  321.       -length_diff : length_diff);
  322.     for (length= (int) key_length-b_length; length-- > 0 ;)
  323.     {
  324.       if (*a++ != ' ')
  325. return ((keyseg->base.flag & HA_REVERSE_SORT) ? -1 : 1);
  326.     }
  327.   }
  328.   if (nextflag & SEARCH_NO_FIND) /* Find record after key */
  329.     return (nextflag & SEARCH_BIGGER) ? -1 : 1;
  330.   return 0;
  331. }
  332. else
  333. {
  334.   if (length_diff)
  335.     return ((keyseg->base.flag & HA_REVERSE_SORT) ?
  336.     -length_diff : length_diff);
  337. }
  338. a=as+ (uint) *as+1 ; b= bs+ b_length+1; /* to next key */
  339.       }
  340.       else
  341.       {
  342. #ifdef USE_STRCOLL
  343.         if (use_strcoll(default_charset_info)) {
  344.           if (((enum ha_base_keytype) keyseg->base.type) == HA_KEYTYPE_BINARY)
  345.           {
  346.             while (a < end)
  347.               if ((flag= (int) *a++ - (int) *b++))
  348.                 return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  349.           }
  350.           else
  351.           {
  352.             if ((flag = my_strnncoll(default_charset_info,
  353.      a, (int) (end-a), b, (int) (end-a))))
  354.               return (keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag;
  355.             b+= (uint) (end-a);
  356.             a=end;
  357.           }
  358.         }
  359.         else
  360. #endif
  361. {
  362.           while (a < end)
  363.             if ((flag= (int) *a++ - (int) *b++))
  364.               return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  365. }
  366.       }
  367.       break;
  368.     case HA_KEYTYPE_INT8:
  369.     {
  370.       int i_1= (int) *((signed char*) a);
  371.       int i_2= (int) *((signed char*) b);
  372.       if ((flag = CMP(i_1,i_2)))
  373. return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  374.       a= end;
  375.       b++;
  376.       break;
  377.     }
  378.     case HA_KEYTYPE_SHORT_INT:
  379.       shortget(s_1,a);
  380.       shortget(s_2,b);
  381.       if ((flag = CMP(s_1,s_2)))
  382. return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  383.       a=  end;
  384.       b+= 2; /* sizeof(short int); */
  385.       break;
  386.     case HA_KEYTYPE_USHORT_INT:
  387.       {
  388. uint16 us_1,us_2;
  389. ushortget(us_1,a);
  390. ushortget(us_2,b);
  391. if ((flag = CMP(us_1,us_2)))
  392.   return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  393. a=  end;
  394. b+=2; /* sizeof(short int); */
  395. break;
  396.       }
  397.     case HA_KEYTYPE_LONG_INT:
  398.       longget(l_1,a);
  399.       longget(l_2,b);
  400.       if ((flag = CMP(l_1,l_2)))
  401. return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  402.       a=  end;
  403.       b+= 4; /* sizeof(long int); */
  404.       break;
  405.     case HA_KEYTYPE_ULONG_INT:
  406.       ulongget(u_1,a);
  407.       ulongget(u_2,b);
  408.       if ((flag = CMP(u_1,u_2)))
  409. return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  410.       a=  end;
  411.       b+= 4; /* sizeof(long int); */
  412.       break;
  413.     case HA_KEYTYPE_INT24:
  414.       l_1=sint3korr(a);
  415.       l_2=sint3korr(b);
  416.       if ((flag = CMP(l_1,l_2)))
  417. return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  418.       a=  end;
  419.       b+= 3;
  420.       break;
  421.     case HA_KEYTYPE_UINT24:
  422.       l_1=(long) uint3korr(a);
  423.       l_2=(long) uint3korr(b);
  424.       if ((flag = CMP(l_1,l_2)))
  425. return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  426.       a=  end;
  427.       b+= 3;
  428.       break;
  429.     case HA_KEYTYPE_FLOAT:
  430.       bmove((byte*) &f_1,(byte*) a,(int) sizeof(float));
  431.       bmove((byte*) &f_2,(byte*) b,(int) sizeof(float));
  432.       if ((flag = CMP(f_1,f_2)))
  433. return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  434.       a=  end;
  435.       b+= sizeof(float);
  436.       break;
  437.     case HA_KEYTYPE_DOUBLE:
  438.       doubleget(d_1,a);
  439.       doubleget(d_2,b);
  440.       if ((flag = CMP(d_1,d_2)))
  441. return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  442.       a=  end;
  443.       b+= sizeof(double);
  444.       break;
  445.     case HA_KEYTYPE_NUM: /* Numeric key */
  446.     {
  447.       int swap_flag=keyseg->base.flag & HA_REVERSE_SORT;
  448.       if (keyseg->base.flag & HA_SPACE_PACK)
  449.       {
  450. int alength,blength;
  451. if (swap_flag)
  452.   swap(uchar*,a,b);
  453. alength= *a++; blength= *b++;
  454. if ((flag=(int) (keyseg->base.length-key_length)) < 0)
  455.   flag=0;
  456. if (alength != blength+flag)
  457. {
  458.   if ((alength > blength+flag && *a != '-') ||
  459.       (alength < blength+flag && *b == '-'))
  460.     return 1;
  461.   else
  462.     return -1;
  463. }
  464. if (*a == '-' && *b == '-')
  465. {
  466.   swap_flag=1;
  467.   swap(uchar*,a,b);
  468. }
  469. end=a+alength;
  470. while (a < end)
  471.   if (*a++ !=  *b++)
  472.   {
  473.     a--; b--;
  474.     if (isdigit((char) *a) && isdigit((char) *b))
  475.       return ((int) *a - (int) *b);
  476.     if (*a == '-' || isdigit((char) *b))
  477.       return (-1);
  478.     if (*b == '-' || *b++ == ' ' || isdigit((char) *a))
  479.       return (1);
  480.     if (*a++ == ' ')
  481.       return (-1);
  482.   }
  483.       }
  484.       else
  485.       {
  486. for ( ; a < end && *a == ' ' && *b == ' ' ; a++, b++) ;
  487. if (*a == '-' && *b == '-')
  488.   swap_flag=1;
  489. if (swap_flag)
  490. {
  491.   end=b+(int) (end-a);
  492.   swap(uchar*,a,b);
  493. }
  494. while (a < end)
  495.   if (*a++ != *b++)
  496.   {
  497.     a--; b--;
  498.     if (isdigit((char) *a) && isdigit((char) *b))
  499.       return ((int) *a - (int) *b);
  500.     if (*a == '-' || isdigit((char) *b))
  501.       return (-1);
  502.     if (*b == '-' || *b++ == ' ' || isdigit((char) *a))
  503.       return (1);
  504.     if (*a++ == ' ')
  505.       return -1;
  506.   }
  507.       }
  508.       if (swap_flag)
  509. swap(uchar*,a,b);
  510.       break;
  511.     }
  512. #ifdef HAVE_LONG_LONG
  513.     case HA_KEYTYPE_LONGLONG:
  514.     {
  515.       longlong ll_a,ll_b;
  516.       longlongget(ll_a,a);
  517.       longlongget(ll_b,b);
  518.       if ((flag = CMP(ll_a,ll_b)))
  519. return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  520.       a=  end;
  521.       b+= sizeof(longlong);
  522.       break;
  523.     }
  524.     case HA_KEYTYPE_ULONGLONG:
  525.     {
  526.       ulonglong ll_a,ll_b;
  527.       longlongget(ll_a,a);
  528.       longlongget(ll_b,b);
  529.       if ((flag = CMP(ll_a,ll_b)))
  530. return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
  531.       a=  end;
  532.       b+= sizeof(ulonglong);
  533.       break;
  534.     }
  535. #endif
  536.     case HA_KEYTYPE_END: /* Ready */
  537.     case HA_KEYTYPE_VARTEXT: /* Impossible */
  538.     case HA_KEYTYPE_VARBINARY: /* Impossible */
  539.       goto end;
  540.     }
  541.   }
  542. end:
  543.   if (!(nextflag & SEARCH_FIND))
  544.   {
  545.     if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
  546.       return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
  547.     LINT_INIT(l_1); LINT_INIT(l_2);
  548.     switch (keyseg->base.length) {
  549.     case 4:
  550.       u_1= (ulong) uint4korr(a);
  551.       u_2= (ulong) uint4korr(b);
  552.       break;
  553.     case 3:
  554.       u_1= (ulong) uint3korr(a);
  555.       u_2= (ulong) uint3korr(b);
  556.       break;
  557.     case 2:
  558.       u_1= (ulong) uint2korr(a);
  559.       u_2= (ulong) uint2korr(b);
  560.       break;
  561.     default: abort(); /* Impossible */
  562.     }
  563.     flag = CMP(u_1,u_2);
  564.     if (nextflag & SEARCH_SAME)
  565.       return (flag); /* read same */
  566.     if (nextflag & SEARCH_BIGGER)
  567.       return (flag <= 0 ? -1 : 1); /* read next */
  568.     return (flag < 0 ? -1 : 1); /* read previous */
  569.   }
  570.   return 0;
  571. } /* _nisam_key_cmp */
  572. /* Get key from key-block */
  573. /* page points at previous key; its advanced to point at next key */
  574. /* key should contain previous key */
  575. /* Returns length of found key + pointers */
  576. /* nod_flag is a flag if we are on nod */
  577. uint _nisam_get_key(register N_KEYDEF *keyinfo, uint nod_flag,
  578.  register uchar **page, register uchar *key)
  579. {
  580.   reg1 N_KEYSEG *keyseg;
  581.   uchar *start,*start_key;
  582.   uint length,c_length;
  583.   LINT_INIT(start);
  584.   start_key=key; c_length=0;
  585.   for (keyseg=keyinfo->seg ; keyseg->base.type ;keyseg++)
  586.   {
  587.     if (keyseg->base.flag & (HA_SPACE_PACK | HA_PACK_KEY))
  588.     {
  589.       start=key;
  590.       if (keyseg->base.flag & HA_SPACE_PACK)
  591. key++;
  592.       if ((length= *(*page)++) & 128)
  593.       {
  594. key+= (c_length=(length & 127));
  595. if (c_length == 0) /* Same key */
  596. {
  597.   key+= *start; /* Same diff_key as prev */
  598.   length=0;
  599. }
  600. else
  601. {
  602.   if (keyseg->base.flag & HA_SPACE_PACK)
  603.     length= *(*page)++;
  604.   else
  605.     length=keyseg->base.length-length+128; /* Rest of key */
  606.   /* Prevent core dumps if wrong data formats */
  607.   if (length > keyseg->base.length)
  608.     length=0;
  609. }
  610.       }
  611.     }
  612.     else
  613.       length=keyseg->base.length;
  614.     memcpy((byte*) key,(byte*) *page,(size_t) length); key+=length;
  615.     if (keyseg->base.flag & HA_SPACE_PACK)
  616.       *start= (uchar) ((key-start)-1);
  617.     *page+=length;
  618.   }
  619.   length=keyseg->base.length+nod_flag;
  620.   bmove((byte*) key,(byte*) *page,length);
  621.   *page+=length;
  622.   return((uint) (key-start_key)+keyseg->base.length);
  623. } /* _nisam_get_key */
  624. /* same as _nisam_get_key but used with fixed length keys */
  625. uint _nisam_get_static_key(register N_KEYDEF *keyinfo, uint nod_flag, register uchar **page, register uchar *key)
  626. {
  627.   memcpy((byte*) key,(byte*) *page,
  628.  (size_t) (keyinfo->base.keylength+nod_flag));
  629.   *page+=keyinfo->base.keylength+nod_flag;
  630.   return(keyinfo->base.keylength);
  631. } /* _nisam_get_static_key */
  632. /* Get last key from key-block, starting from keypos */
  633. /* Return pointer to where keystarts */
  634. uchar *_nisam_get_last_key(N_INFO *info, N_KEYDEF *keyinfo, uchar *keypos, uchar *lastkey, uchar *endpos)
  635. {
  636.   uint nod_flag;
  637.   uchar *lastpos;
  638.   nod_flag=test_if_nod(keypos);
  639.   if (! (keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED)))
  640.   {
  641.     lastpos=endpos-keyinfo->base.keylength-nod_flag;
  642.     if (lastpos > keypos)
  643.       bmove((byte*) lastkey,(byte*) lastpos,keyinfo->base.keylength+nod_flag);
  644.   }
  645.   else
  646.   {
  647.     lastpos=0 ; keypos+=2+nod_flag;
  648.     lastkey[0]=0;
  649.     while (keypos < endpos)
  650.     {
  651.       lastpos=keypos;
  652.       VOID(_nisam_get_key(keyinfo,nod_flag,&keypos,lastkey));
  653.     }
  654.   }
  655.   return lastpos;
  656. } /* _nisam_get_last_key */
  657. /* Calculate length of key */
  658. uint _nisam_keylength(N_KEYDEF *keyinfo, register uchar *key)
  659. {
  660.   reg1 N_KEYSEG *keyseg;
  661.   uchar *start;
  662.   if (! (keyinfo->base.flag & HA_SPACE_PACK_USED))
  663.     return (keyinfo->base.keylength);
  664.   start=key;
  665.   for (keyseg=keyinfo->seg ; keyseg->base.type ; keyseg++)
  666.   {
  667.     if (keyseg->base.flag & HA_SPACE_PACK)
  668.       key+= *key+1;
  669.     else
  670.       key+= keyseg->base.length;
  671.   }
  672.   return((uint) (key-start)+keyseg->base.length);
  673. } /* _nisam_keylength */
  674. /* Move a key */
  675. uchar *_nisam_move_key(N_KEYDEF *keyinfo, uchar *to, uchar *from)
  676. {
  677.   reg1 uint length;
  678.   memcpy((byte*) to, (byte*) from,
  679.  (size_t) (length=_nisam_keylength(keyinfo,from)));
  680.   return to+length;
  681. }
  682. /* Find next/previous record with same key */
  683. /* This can't be used when database is touched after last read */
  684. int _nisam_search_next(register N_INFO *info, register N_KEYDEF *keyinfo,
  685.     uchar *key, uint nextflag, ulong pos)
  686. {
  687.   int error;
  688.   uint nod_flag;
  689.   uchar lastkey[N_MAX_KEY_BUFF];
  690.   DBUG_ENTER("_nisam_search_next");
  691.   DBUG_PRINT("enter",("nextflag: %d  lastpos: %d  int_keypos: %lx",
  692.        nextflag,info->lastpos,info->int_keypos));
  693.   DBUG_EXECUTE("key",_nisam_print_key(DBUG_FILE,keyinfo->seg,key););
  694.   if ((nextflag & SEARCH_BIGGER && info->int_keypos >= info->int_maxpos) ||
  695.       info->int_pos == NI_POS_ERROR || info->page_changed)
  696.     DBUG_RETURN(_nisam_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF,
  697.    pos));
  698.   if (info->buff_used)
  699.   {
  700.     if (!_nisam_fetch_keypage(info,keyinfo,info->last_search_keypage,
  701.       info->buff,0))
  702.     {
  703.       info->lastpos= NI_POS_ERROR;
  704.       DBUG_RETURN(-1);
  705.     }
  706.     info->buff_used=0;
  707.   }
  708.   /* Last used buffer is in info->buff */
  709.   nod_flag=test_if_nod(info->buff);
  710.   VOID(_nisam_move_key(keyinfo,lastkey,key));
  711.   if (nextflag & SEARCH_BIGGER) /* Next key */
  712.   {
  713.     ulong tmp_pos=_nisam_kpos(nod_flag,info->int_keypos);
  714.     if (tmp_pos != NI_POS_ERROR)
  715.     {
  716.       if ((error=_nisam_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF,
  717.     tmp_pos)) <=0)
  718. DBUG_RETURN(error);
  719.     }
  720.     VOID((*keyinfo->get_key)(keyinfo,nod_flag,&info->int_keypos,lastkey));
  721.   }
  722.   else /* Previous key */
  723.   {
  724.     info->int_keypos=_nisam_get_last_key(info,keyinfo,info->buff,lastkey,
  725.       info->int_keypos);
  726.     if (info->int_keypos == info->buff+2)
  727.       DBUG_RETURN(_nisam_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF,
  728.      pos));
  729.     if ((error=_nisam_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF,
  730.   _nisam_kpos(nod_flag,info->int_keypos))) <= 0)
  731.       DBUG_RETURN(error);
  732.   }
  733.   info->int_keypos=_nisam_get_last_key(info,keyinfo,info->buff,lastkey,
  734.     info->int_keypos);
  735.   VOID(_nisam_move_key(keyinfo,info->lastkey,lastkey));
  736.   VOID((*keyinfo->get_key)(keyinfo,nod_flag,&info->int_keypos,info->lastkey));
  737.   info->lastpos=_nisam_dpos(info,nod_flag,info->int_keypos);
  738.   DBUG_PRINT("exit",("found key at %d",info->lastpos));
  739.   DBUG_RETURN(0);
  740. } /* _nisam_search_next */
  741. /* S|ker reda p} positionen f|r f|rsta recordet i ett index */
  742. /* Positionen l{ggs i info->lastpos */
  743. int _nisam_search_first(register N_INFO *info, register N_KEYDEF *keyinfo, register ulong pos)
  744. {
  745.   uint nod_flag;
  746.   uchar *page;
  747.   DBUG_ENTER("_nisam_search_first");
  748.   if (pos == NI_POS_ERROR)
  749.   {
  750.     my_errno=HA_ERR_KEY_NOT_FOUND;
  751.     info->lastpos= NI_POS_ERROR;
  752.     DBUG_RETURN(-1);
  753.   }
  754.   do
  755.   {
  756.     if (!_nisam_fetch_keypage(info,keyinfo,pos,info->buff,0))
  757.     {
  758.       info->lastpos= NI_POS_ERROR;
  759.       DBUG_RETURN(-1);
  760.     }
  761.     nod_flag=test_if_nod(info->buff);
  762.     page=info->buff+2+nod_flag;
  763.   } while ((pos=_nisam_kpos(nod_flag,page)) != NI_POS_ERROR);
  764.   VOID((*keyinfo->get_key)(keyinfo,nod_flag,&page,info->lastkey));
  765.   info->int_keypos=page; info->int_maxpos=info->buff+getint(info->buff)-1;
  766.   info->lastpos=_nisam_dpos(info,nod_flag,page);
  767.   info->page_changed=info->buff_used=0;
  768.   info->last_search_keypage=info->int_pos;
  769.   DBUG_PRINT("exit",("found key at %d",info->lastpos));
  770.   DBUG_RETURN(0);
  771. } /* _nisam_search_first */
  772. /* S|ker reda p} positionen f|r sista recordet i ett index */
  773. /* Positionen l{ggs i info->lastpos */
  774. int _nisam_search_last(register N_INFO *info, register N_KEYDEF *keyinfo, register ulong pos)
  775. {
  776.   uint nod_flag;
  777.   uchar *buff,*page;
  778.   DBUG_ENTER("_nisam_search_last");
  779.   if (pos == NI_POS_ERROR)
  780.   {
  781.     my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
  782.     info->lastpos= NI_POS_ERROR;
  783.     DBUG_RETURN(-1);
  784.   }
  785.   buff=info->buff;
  786.   do
  787.   {
  788.     if (!_nisam_fetch_keypage(info,keyinfo,pos,buff,0))
  789.     {
  790.       info->lastpos= NI_POS_ERROR;
  791.       DBUG_RETURN(-1);
  792.     }
  793.     page= buff+getint(buff);
  794.     nod_flag=test_if_nod(buff);
  795.   } while ((pos=_nisam_kpos(nod_flag,page)) != NI_POS_ERROR);
  796.   VOID(_nisam_get_last_key(info,keyinfo,buff,info->lastkey,page));
  797.   info->lastpos=_nisam_dpos(info,nod_flag,page);
  798.   info->int_keypos=info->int_maxpos=page;
  799.   info->page_changed=info->buff_used=0;
  800.   info->last_search_keypage=info->int_pos;
  801.   DBUG_PRINT("exit",("found key at %d",info->lastpos));
  802.   DBUG_RETURN(0);
  803. } /* _nisam_search_last */