write.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:26k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /* Skriver ett record till en isam-databas */
  14. #include "isamdef.h"
  15. #ifdef __WIN__
  16. #include <errno.h>
  17. #endif
  18. /* Functions declared in this file */
  19. static int w_search(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,
  20.     ulong pos, uchar *father_buff, uchar *father_keypos,
  21.     ulong father_page);
  22. static int _nisam_balance_page(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,
  23.     uchar *curr_buff,uchar *father_buff,
  24.     uchar *father_keypos,ulong father_page);
  25. /* Write new record to database */
  26. int nisam_write(N_INFO *info, const byte *record)
  27. {
  28.   uint i;
  29.   ulong filepos;
  30.   uchar *buff;
  31.   DBUG_ENTER("nisam_write");
  32.   DBUG_PRINT("enter",("isam: %d  data: %d",info->s->kfile,info->dfile));
  33.   if (info->s->base.options & HA_OPTION_READ_ONLY_DATA)
  34.   {
  35.     my_errno=EACCES;
  36.     DBUG_RETURN(-1);
  37.   }
  38. #ifndef NO_LOCKING
  39.   if (_nisam_readinfo(info,F_WRLCK,1)) DBUG_RETURN(-1);
  40. #endif
  41.   dont_break(); /* Dont allow SIGHUP or SIGINT */
  42. #if !defined(NO_LOCKING) && defined(USE_RECORD_LOCK)
  43.   if (!info->locked && my_lock(info->dfile,F_WRLCK,0L,F_TO_EOF,
  44.        MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
  45.     goto err;
  46. #endif
  47.   filepos= ((info->s->state.dellink != NI_POS_ERROR) ?
  48.     info->s->state.dellink :
  49.     info->s->state.data_file_length);
  50.   if (info->s->base.reloc == 1L && info->s->base.records == 1L &&
  51.       info->s->state.records == 1L)
  52.   { /* System file */
  53.     my_errno=HA_ERR_RECORD_FILE_FULL;
  54.     goto err2;
  55.   }
  56.   if (info->s->state.key_file_length >=
  57.       info->s->base.max_key_file_length -
  58.       info->s->blocksize* INDEX_BLOCK_MARGIN *info->s->state.keys)
  59.   {
  60.     my_errno=HA_ERR_INDEX_FILE_FULL;
  61.     goto err2;
  62.   }
  63. /* Write all keys to indextree */
  64.   buff=info->lastkey+info->s->base.max_key_length;
  65.   for (i=0 ; i < info->s->state.keys ; i++)
  66.   {
  67.     VOID(_nisam_make_key(info,i,buff,record,filepos));
  68.     if (_nisam_ck_write(info,i,buff)) goto err;
  69.   }
  70.   if ((*info->s->write_record)(info,record))
  71.     goto err;
  72.   info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED |HA_STATE_AKTIV |
  73.  HA_STATE_WRITTEN);
  74.   info->s->state.records++;
  75.   info->lastpos=filepos;
  76.   nisam_log_record(LOG_WRITE,info,record,filepos,0);
  77.   VOID(_nisam_writeinfo(info,1));
  78.   allow_break(); /* Allow SIGHUP & SIGINT */
  79.   DBUG_RETURN(0);
  80. err:
  81.   if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL)
  82.   {
  83.     info->errkey= (int) i;
  84.     while ( i-- > 0)
  85.     {
  86.       VOID(_nisam_make_key(info,i,buff,record,filepos));
  87.       if (_nisam_ck_delete(info,i,buff))
  88. break;
  89.     }
  90.   }
  91.   info->update=(HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_WRITTEN);
  92. err2:
  93.   nisam_log_record(LOG_WRITE,info,record,filepos,my_errno);
  94.   VOID(_nisam_writeinfo(info,1));
  95.   allow_break(); /* Allow SIGHUP & SIGINT */
  96.   DBUG_RETURN(-1);
  97. } /* nisam_write */
  98. /* Write one key to btree */
  99. int _nisam_ck_write(register N_INFO *info, uint keynr, uchar *key)
  100. {
  101.   int error;
  102.   DBUG_ENTER("_nisam_ck_write");
  103.   if ((error=w_search(info,info->s->keyinfo+keynr,key,
  104.       info->s->state.key_root[keynr], (uchar *) 0, (uchar*) 0,
  105.       0L)) > 0)
  106.     error=_nisam_enlarge_root(info,keynr,key);
  107.   DBUG_RETURN(error);
  108. } /* _nisam_ck_write */
  109. /* Make a new root with key as only pointer */
  110. int _nisam_enlarge_root(register N_INFO *info, uint keynr, uchar *key)
  111. {
  112.   uint t_length,nod_flag;
  113.   reg2 N_KEYDEF *keyinfo;
  114.   S_PARAM s_temp;
  115.   ISAM_SHARE *share=info->s;
  116.   DBUG_ENTER("_nisam_enlarge_root");
  117.   info->page_changed=1;
  118.   nod_flag= (share->state.key_root[keynr] != NI_POS_ERROR) ?
  119.     share->base.key_reflength : 0;
  120.   _nisam_kpointer(info,info->buff+2,share->state.key_root[keynr]); /* if nod */
  121.   keyinfo=share->keyinfo+keynr;
  122.   t_length=_nisam_get_pack_key_length(keyinfo,nod_flag,(uchar*) 0,(uchar*) 0,
  123.    key,&s_temp);
  124.   putint(info->buff,t_length+2+nod_flag,nod_flag);
  125.   _nisam_store_key(keyinfo,info->buff+2+nod_flag,&s_temp);
  126.   if ((share->state.key_root[keynr]= _nisam_new(info,keyinfo)) ==
  127.       NI_POS_ERROR ||
  128.       _nisam_write_keypage(info,keyinfo,share->state.key_root[keynr],info->buff))
  129.     DBUG_RETURN(-1);
  130.   DBUG_RETURN(0);
  131. } /* _nisam_enlarge_root */
  132. /* S|ker reda p} vart nyckeln skall s{ttas och placerar den dit */
  133. /* Returnerar -1 om fel ; 0 om ok.  1 om nyckel propagerar upp}t */
  134. static int w_search(register N_INFO *info, register N_KEYDEF *keyinfo,
  135.     uchar *key, ulong page, uchar *father_buff,
  136.     uchar *father_keypos, ulong father_page)
  137. {
  138.   int error,flag;
  139.   uint comp_flag,nod_flag;
  140.   uchar *temp_buff,*keypos;
  141.   uchar keybuff[N_MAX_KEY_BUFF];
  142.   DBUG_ENTER("w_search");
  143.   DBUG_PRINT("enter",("page: %ld",page));
  144.   if (page == NI_POS_ERROR)
  145.     DBUG_RETURN(1); /* No key, make new */
  146.   if (keyinfo->base.flag & HA_SORT_ALLOWS_SAME)
  147.     comp_flag=SEARCH_BIGGER; /* Put after same key */
  148.   else if (keyinfo->base.flag & HA_NOSAME)
  149.     comp_flag=SEARCH_FIND; /* No dupplicates */
  150.   else
  151.     comp_flag=SEARCH_SAME; /* Keys in rec-pos order */
  152.   if (!(temp_buff= (uchar*) my_alloca((uint) keyinfo->base.block_length+
  153.       N_MAX_KEY_BUFF)))
  154.     DBUG_RETURN(-1);
  155.   if (!_nisam_fetch_keypage(info,keyinfo,page,temp_buff,0))
  156.     goto err;
  157.   flag=(*keyinfo->bin_search)(info,keyinfo,temp_buff,key,0,comp_flag,&keypos,
  158.       keybuff);
  159.   nod_flag=test_if_nod(temp_buff);
  160.   if (flag == 0)
  161.   {
  162.     my_errno=HA_ERR_FOUND_DUPP_KEY;
  163. /* get position to record with dupplicated key */
  164.     VOID((*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff));
  165.     info->dupp_key_pos=_nisam_dpos(info,test_if_nod(temp_buff),keypos);
  166.     my_afree((byte*) temp_buff);
  167.     DBUG_RETURN(-1);
  168.   }
  169.   if ((error=w_search(info,keyinfo,key,_nisam_kpos(nod_flag,keypos),
  170.       temp_buff,keypos,page)) >0)
  171.   {
  172.     error=_nisam_insert(info,keyinfo,key,temp_buff,keypos,keybuff,father_buff,
  173.      father_keypos,father_page);
  174.     if (_nisam_write_keypage(info,keyinfo,page,temp_buff))
  175.       goto err;
  176.   }
  177.   my_afree((byte*) temp_buff);
  178.   DBUG_RETURN(error);
  179. err:
  180.   my_afree((byte*) temp_buff);
  181.   DBUG_PRINT("exit",("Error: %d",my_errno));
  182.   DBUG_RETURN (-1);
  183. } /* w_search */
  184. /* Insert new key at right of key_pos */
  185. /* Returns 2 if key contains key to upper level */
  186. int _nisam_insert(register N_INFO *info, register N_KEYDEF *keyinfo,
  187.        uchar *key, uchar *anc_buff, uchar *key_pos, uchar *key_buff,
  188.        uchar *father_buff, uchar *father_key_pos, ulong father_page)
  189. {
  190.   uint a_length,t_length,nod_flag;
  191.   uchar *endpos;
  192.   int key_offset;
  193.   S_PARAM s_temp;
  194.   DBUG_ENTER("_nisam_insert");
  195.   DBUG_PRINT("enter",("key_pos: %lx",key_pos));
  196.   DBUG_EXECUTE("key",_nisam_print_key(DBUG_FILE,keyinfo->seg,key););
  197.   nod_flag=test_if_nod(anc_buff);
  198.   a_length=getint(anc_buff);
  199.   endpos= anc_buff+ a_length;
  200.   t_length=_nisam_get_pack_key_length(keyinfo,nod_flag,
  201.    (key_pos == endpos ? (uchar*) 0 : key_pos),
  202.    (key_pos == anc_buff+2+nod_flag ?
  203.     (uchar*) 0 : key_buff),key,&s_temp);
  204. #ifndef DBUG_OFF
  205.   if (key_pos != anc_buff+2+nod_flag)
  206.     DBUG_DUMP("prev_key",(byte*) key_buff,_nisam_keylength(keyinfo,key_buff));
  207.   if (keyinfo->base.flag & HA_PACK_KEY)
  208.   {
  209.     DBUG_PRINT("test",("t_length: %d  ref_len: %d",
  210.        t_length,s_temp.ref_length));
  211.     DBUG_PRINT("test",("n_ref_len: %d  n_length: %d  key: %lx",
  212.        s_temp.n_ref_length,s_temp.n_length,s_temp.key));
  213.   }
  214. #endif
  215.   key_offset = (uint)(endpos-key_pos);
  216.   if((int) t_length < 0)
  217.     key_offset += (int) t_length;
  218.   if (key_offset < 0)
  219.   {
  220.     DBUG_PRINT("error",("Found a bug: negative key_offset %dn", key_offset));
  221.     DBUG_RETURN(-1);
  222.   }
  223.   if ((int) t_length >= 0) /* t_length is almost always > 0 */
  224.     bmove_upp((byte*) endpos+t_length,(byte*) endpos,(uint)key_offset );
  225.   else
  226.   {
  227.     /* This may happen if a key was deleted and the next key could be
  228.        compressed better than before */
  229.     DBUG_DUMP("anc_buff",(byte*) anc_buff,a_length);
  230.     bmove(key_pos,key_pos - (int) t_length,(uint)key_offset);
  231.   }
  232.   _nisam_store_key(keyinfo,key_pos,&s_temp);
  233.   a_length+=t_length;
  234.   putint(anc_buff,a_length,nod_flag);
  235.   if (a_length <= keyinfo->base.block_length)
  236.     DBUG_RETURN(0); /* There is room on page */
  237.   /* Page is full */
  238.   if (!(keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED)) &&
  239.       father_buff)
  240.     DBUG_RETURN(_nisam_balance_page(info,keyinfo,key,anc_buff,father_buff,
  241.  father_key_pos,father_page));
  242.   DBUG_RETURN(_nisam_splitt_page(info,keyinfo,key,anc_buff,key_buff));
  243. } /* _nisam_insert */
  244. /* splitt a full page in two and assign emerging item to key */
  245. int _nisam_splitt_page(register N_INFO *info, register N_KEYDEF *keyinfo,
  246.     uchar *key, uchar *buff, uchar *key_buff)
  247. {
  248.   uint length,a_length,key_ref_length,t_length,nod_flag;
  249.   uchar *key_pos,*pos;
  250.   ulong new_pos;
  251.   S_PARAM s_temp;
  252.   DBUG_ENTER("ni_splitt_page");
  253.   DBUG_DUMP("buff",(byte*) buff,getint(buff));
  254.   nod_flag=test_if_nod(buff);
  255.   key_ref_length=2+nod_flag;
  256.   key_pos=_nisam_find_half_pos(info,keyinfo,buff,key_buff);
  257.   length=(uint) (key_pos-buff);
  258.   a_length=getint(buff);
  259.   putint(buff,length,nod_flag);
  260.   info->page_changed=1;
  261. /* Correct new page pointer */
  262.   VOID((*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff));
  263.   if (nod_flag)
  264.   {
  265.     DBUG_PRINT("test",("Splitting nod"));
  266.     pos=key_pos-nod_flag;
  267.     memcpy((byte*) info->buff+2,(byte*) pos,(size_t) nod_flag);
  268.   }
  269. /* Move midle item to key and pointer to new page */
  270.   if ((new_pos=_nisam_new(info,keyinfo)) == NI_POS_ERROR)
  271.     DBUG_RETURN(-1);
  272.   _nisam_kpointer(info,_nisam_move_key(keyinfo,key,key_buff),new_pos);
  273. /* Store new page */
  274.   VOID((*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff));
  275.   t_length=_nisam_get_pack_key_length(keyinfo,nod_flag,(uchar *) 0, (uchar*) 0,
  276.    key_buff, &s_temp);
  277.   s_temp.n_length= *key_pos; /* Needed by ni_store_key */
  278.   length=(uint) ((buff+a_length)-key_pos);
  279.   memcpy((byte*) info->buff+key_ref_length+t_length,(byte*) key_pos,
  280.  (size_t) length);
  281.   _nisam_store_key(keyinfo,info->buff+key_ref_length,&s_temp);
  282.   putint(info->buff,length+t_length+key_ref_length,nod_flag);
  283.   if (_nisam_write_keypage(info,keyinfo,new_pos,info->buff))
  284.     DBUG_RETURN(-1);
  285.   DBUG_DUMP("key",(byte*) key,_nisam_keylength(keyinfo,key));
  286.   DBUG_RETURN(2); /* Middle key up */
  287. } /* _nisam_splitt_page */
  288. /* find out how much more room a key will take */
  289. #ifdef QQ
  290. uint _nisam_get_pack_key_length(N_KEYDEF *keyinfo, uint nod_flag, uchar *key_pos, uchar *key_buff, uchar *key, S_PARAM *s_temp)
  291. /* If nod: Length of nod-pointer */
  292. /* Position to pos after key in buff */
  293. /* Last key before current key */
  294. /* Current key */
  295. /* How next key will be packed */
  296. {
  297.   reg1 N_KEYSEG *keyseg;
  298.   int length;
  299.   uint key_length,ref_length,n_length,diff_flag,same_length;
  300.   uchar *start,*end,*key_end;
  301.   s_temp->key=key;
  302.   if (!(keyinfo->base.flag & HA_PACK_KEY))
  303.     return (s_temp->totlength=_nisam_keylength(keyinfo,key)+nod_flag);
  304.   s_temp->ref_length=s_temp->n_ref_length=s_temp->n_length=0;
  305.   s_temp->prev_length=0;
  306.   same_length=0; keyseg=keyinfo->seg;
  307.   key_length=_nisam_keylength(keyinfo,key)+nod_flag;
  308.   if (keyseg->base.flag & HA_SPACE_PACK)
  309.   {
  310.     diff_flag=1;
  311.     end=key_end= key+ *key+1;
  312.     if (key_buff)
  313.     {
  314.       if (*key == *key_buff && *key)
  315. same_length=1; /* Don't use key-pack if length == 0 */
  316.       else if (*key > *key_buff)
  317. end=key+ *key_buff+1;
  318.       key_buff++;
  319.     }
  320.     key++;
  321.   }
  322.   else
  323.   {
  324.     diff_flag=0;
  325.     key_end=end= key+keyseg->base.length;
  326.   }
  327.   start=key;
  328.   if (key_buff)
  329.     while (key < end && *key == *key_buff)
  330.     {
  331.       key++; key_buff++;
  332.     }
  333.   s_temp->key=key; s_temp->key_length= (uint) (key_end-key);
  334.   if (same_length && key == key_end)
  335.   {
  336.     s_temp->ref_length=128;
  337.     length=(int) key_length-(int)(key_end-start); /* Same as prev key */
  338.     if (key_pos)
  339.     {
  340.       s_temp->n_length= *key_pos;
  341.       key_pos=0; /* Can't combine with next */
  342.     }
  343.   }
  344.   else
  345.   {
  346.     if (start != key)
  347.     { /* Starts as prev key */
  348.       s_temp->ref_length= (uint) (key-start)+128;
  349.       length=(int) (1+key_length-(uint) (key-start));
  350.     }
  351.     else
  352.       length=(int) (key_length+ (1-diff_flag)); /* Not packed key */
  353.   }
  354.   s_temp->totlength=(uint) length;
  355.   DBUG_PRINT("test",("tot_length: %d  length: %d  uniq_key_length: %d",
  356.      key_length,length,s_temp->key_length));
  357. /* If something after that is not 0 length test if we can combine */
  358.   if (key_pos && (n_length= *key_pos))
  359.   {
  360.     key_pos++;
  361.     ref_length=0;
  362.     if (n_length & 128)
  363.     {
  364.       if ((ref_length=n_length & 127))
  365. if (diff_flag)
  366.   n_length= *key_pos++; /* Length of key-part */
  367. else
  368.   n_length=keyseg->base.length - ref_length;
  369.     }
  370.     else
  371.       if (*start == *key_pos && diff_flag && start != key_end)
  372. length++; /* One new pos for ref.len */
  373.     DBUG_PRINT("test",("length: %d  key_pos: %lx",length,key_pos));
  374.     if (n_length != 128)
  375.     { /* Not same key after */
  376.       key=start+ref_length;
  377.       while (n_length > 0 && key < key_end && *key == *key_pos)
  378.       {
  379. key++; key_pos++;
  380. ref_length++;
  381. n_length--;
  382. length--; /* We gained one char */
  383.       }
  384.       if (n_length == 0 && diff_flag)
  385.       {
  386. n_length=128; /* Same as prev key */
  387. length--; /* We don't need key-length */
  388.       }
  389.       else if (ref_length)
  390. s_temp->n_ref_length=ref_length | 128;
  391.     }
  392.     s_temp->n_length=n_length;
  393.   }
  394.   return (uint) length;
  395. } /* _nisam_get_pack_key_length */
  396. #else
  397. uint
  398. _nisam_get_pack_key_length(N_KEYDEF *keyinfo,
  399. uint nod_flag,  /* If nod: Length of nod-pointer */
  400. uchar *key_pos, /* Position to pos after key in buff */
  401. uchar *key_buff,/* Last key before current key */
  402. uchar *key, /* Current key */
  403. S_PARAM *s_temp/* How next key will be packed */
  404. )
  405. {
  406.   reg1 N_KEYSEG *keyseg;
  407.   int length;
  408.   uint key_length,ref_length,n_length,diff_flag,same_length,org_key_length=0;
  409.   uchar *start,*end,*key_end;
  410.   s_temp->key=key;
  411.   if (!(keyinfo->base.flag & HA_PACK_KEY))
  412.     return (s_temp->totlength=_nisam_keylength(keyinfo,key)+nod_flag);
  413.   s_temp->ref_length=s_temp->n_ref_length=s_temp->n_length=0;
  414.   same_length=0; keyseg=keyinfo->seg;
  415.   key_length=_nisam_keylength(keyinfo,key)+nod_flag;
  416.   s_temp->prev_key=key_buff;
  417.   if (keyseg->base.flag & HA_SPACE_PACK)
  418.   {
  419.     diff_flag=1;
  420.     end=key_end= key+ *key+1;
  421.     if (key_buff)
  422.     {
  423.       org_key_length= (uint) *key_buff;
  424.       if (*key == *key_buff && *key)
  425. same_length=1; /* Don't use key-pack if length == 0 */
  426.       else if (*key > *key_buff)
  427. end=key+ org_key_length+1;
  428.       key_buff++;
  429.     }
  430.     key++;
  431.   }
  432.   else
  433.   {
  434.     diff_flag=0;
  435.     key_end=end= key+(org_key_length=keyseg->base.length);
  436.   }
  437.   start=key;
  438.   if (key_buff)
  439.     while (key < end && *key == *key_buff)
  440.     {
  441.       key++; key_buff++;
  442.     }
  443.   s_temp->key=key; s_temp->key_length= (uint) (key_end-key);
  444.   if (same_length && key == key_end)
  445.   {
  446.     s_temp->ref_length=128;
  447.     length=(int) key_length-(int)(key_end-start); /* Same as prev key */
  448.     if (key_pos)
  449.     { /* Can't combine with next */
  450.       s_temp->n_length= *key_pos; /* Needed by _nisam_store_key */
  451.       key_pos=0;
  452.     }
  453.   }
  454.   else
  455.   {
  456.     if (start != key)
  457.     { /* Starts as prev key */
  458.       s_temp->ref_length= (uint) (key-start)+128;
  459.       length=(int) (1+key_length-(uint) (key-start));
  460.     }
  461.     else
  462.       length=(int) (key_length+ (1-diff_flag)); /* Not packed key */
  463.   }
  464.   s_temp->totlength=(uint) length;
  465.   s_temp->prev_length=0;
  466.   DBUG_PRINT("test",("tot_length: %d  length: %d  uniq_key_length: %d",
  467.      key_length,length,s_temp->key_length));
  468. /* If something after that is not 0 length test if we can combine */
  469.   if (key_pos && (n_length= *key_pos++))
  470.   {
  471.     if (n_length == 128)
  472.     {
  473.       /*
  474. We put a different key between two identical keys
  475. Extend next key to have same prefix as this key
  476.       */
  477.       if (s_temp->ref_length)
  478.       { /* make next key longer */
  479. s_temp->part_of_prev_key= s_temp->ref_length;
  480. s_temp->prev_length=      org_key_length - (s_temp->ref_length-128);
  481. s_temp->n_length=    s_temp->prev_length;
  482. s_temp->prev_key+=        diff_flag + (s_temp->ref_length - 128);
  483. length+=   s_temp->prev_length+diff_flag;
  484.       }
  485.       else
  486.       { /* Can't use prev key */
  487. s_temp->part_of_prev_key=0;
  488. s_temp->prev_length= org_key_length;
  489. s_temp->n_length=    org_key_length;
  490. s_temp->prev_key+=   diff_flag; /* To start of key */
  491. length+=      org_key_length;
  492.       }
  493.       return (uint) length;
  494.     }
  495.     if (n_length & 128)
  496.     {
  497.       ref_length=n_length & 127;
  498.       if (diff_flag) /* If SPACE_PACK */
  499. n_length= *key_pos++; /* Length of key-part */
  500.       else
  501. n_length=keyseg->base.length - ref_length;
  502.       /* Test if new keys has fewer characters that match the previous key */
  503.       if (!s_temp->ref_length)
  504.       { /* Can't use prev key */
  505. s_temp->part_of_prev_key= 0;
  506. s_temp->prev_length=  ref_length;
  507. s_temp->n_length= n_length+ref_length;
  508. s_temp->prev_key+= diff_flag; /* To start of key */
  509. return (uint) length+ref_length-diff_flag;
  510.       }
  511.       if (ref_length+128 > s_temp->ref_length)
  512.       {
  513. /* We must copy characters from the original key to the next key */
  514. s_temp->part_of_prev_key= s_temp->ref_length;
  515. s_temp->prev_length=   ref_length+128 - s_temp->ref_length;
  516. s_temp->n_length=   n_length + s_temp->prev_length;
  517. s_temp->prev_key+=    diff_flag + s_temp->ref_length -128;
  518. return (uint) length + s_temp->prev_length;
  519.       }
  520.     }
  521.     else
  522.     {
  523.       ref_length=0;
  524.       if (*start == *key_pos && diff_flag && start != key_end)
  525. length++; /* One new pos for ref.len */
  526.     }
  527.     DBUG_PRINT("test",("length: %d  key_pos: %lx",length,key_pos));
  528.     key=start+ref_length;
  529.     while (n_length > 0 && key < key_end && *key == *key_pos)
  530.     {
  531.       key++; key_pos++;
  532.       ref_length++;
  533.       n_length--;
  534.       length--; /* We gained one char */
  535.     }
  536.     if (n_length == 0 && diff_flag)
  537.     {
  538.       n_length=128; /* Same as prev key */
  539.       length--; /* We don't need key-length */
  540.     }
  541.     else if (ref_length)
  542.       s_temp->n_ref_length=ref_length | 128;
  543.     s_temp->n_length=n_length;
  544.   }
  545.   return (uint) length;
  546. } /* _nisam_get_pack_key_length */
  547. #endif
  548. /* store a key in page-buffert */
  549. void _nisam_store_key(N_KEYDEF *keyinfo, register uchar *key_pos,
  550.    register S_PARAM *s_temp)
  551. {
  552.   uint length;
  553.   uchar *start;
  554.   if (! (keyinfo->base.flag & HA_PACK_KEY))
  555.   {
  556.     memcpy((byte*) key_pos,(byte*) s_temp->key,(size_t) s_temp->totlength);
  557.     return;
  558.   }
  559.   start=key_pos;
  560.   if ((*key_pos=(uchar) s_temp->ref_length))
  561.     key_pos++;
  562.   if (s_temp->ref_length == 0 ||
  563.       (s_temp->ref_length > 128 &&
  564.        (keyinfo->seg[0].base.flag & HA_SPACE_PACK)))
  565.     *key_pos++= (uchar) s_temp->key_length;
  566.   bmove((byte*) key_pos,(byte*) s_temp->key,
  567. (length=s_temp->totlength-(uint) (key_pos-start)));
  568.   key_pos+=length;
  569.   if (s_temp->prev_length)
  570.   {
  571.     /* Extend next key because new key didn't have same prefix as prev key */
  572.     if (s_temp->part_of_prev_key)
  573.       *key_pos++ = s_temp->part_of_prev_key;
  574.     if (keyinfo->seg[0].base.flag & HA_SPACE_PACK)
  575.       *key_pos++= s_temp->n_length;
  576.     memcpy(key_pos, s_temp->prev_key, s_temp->prev_length);
  577.     return;
  578.   }
  579.   if ((*key_pos = (uchar) s_temp->n_ref_length))
  580.   {
  581.     if (! (keyinfo->seg[0].base.flag & HA_SPACE_PACK))
  582.       return; /* Don't save keylength */
  583.     key_pos++; /* Store ref for next key */
  584.   }
  585.   *key_pos = (uchar) s_temp->n_length;
  586.   return;
  587. } /* _nisam_store_key */
  588. /* Calculate how to much to move to split a page in two */
  589. /* Returns pointer and key for get_key() to get mid key */
  590. /* There is at last 2 keys after pointer in buff */
  591. uchar *_nisam_find_half_pos(N_INFO *info, N_KEYDEF *keyinfo, uchar *page, uchar *key)
  592. {
  593.   uint keys,length,key_ref_length,nod_flag;
  594.   uchar *end,*lastpos;
  595.   DBUG_ENTER("_nisam_find_half_pos");
  596.   nod_flag=test_if_nod(page);
  597.   key_ref_length=2+nod_flag;
  598.   length=getint(page)-key_ref_length;
  599.   page+=key_ref_length;
  600.   if (!(keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED)))
  601.   {
  602.     keys=(length/(keyinfo->base.keylength+nod_flag))/2;
  603.     DBUG_RETURN(page+keys*(keyinfo->base.keylength+nod_flag));
  604.   }
  605.   end=page+length/2-key_ref_length; /* This is aprox. half */
  606.   *key='';
  607.   do
  608.   {
  609.     lastpos=page;
  610.     VOID((*keyinfo->get_key)(keyinfo,nod_flag,&page,key));
  611.    } while (page < end);
  612.    DBUG_PRINT("exit",("returns: %lx  page: %lx  half: %lx",lastpos,page,end));
  613.    DBUG_RETURN(lastpos);
  614. } /* _nisam_find_half_pos */
  615. /* Balance page with not packed keys with page on right/left */
  616. /* returns 0 if balance was done */
  617. static int _nisam_balance_page(register N_INFO *info, N_KEYDEF *keyinfo,
  618.     uchar *key, uchar *curr_buff, uchar *father_buff,
  619.     uchar *father_key_pos, ulong father_page)
  620. {
  621.   my_bool right;
  622.   uint k_length,father_length,father_keylength,nod_flag,curr_keylength,
  623.        right_length,left_length,new_right_length,new_left_length,extra_length,
  624.        length,keys;
  625.   uchar *pos,*buff,*extra_buff;
  626.   ulong next_page,new_pos;
  627.   byte tmp_part_key[N_MAX_KEY_BUFF];
  628.   DBUG_ENTER("_nisam_balance_page");
  629.   k_length=keyinfo->base.keylength;
  630.   father_length=getint(father_buff);
  631.   father_keylength=k_length+info->s->base.key_reflength;
  632.   nod_flag=test_if_nod(curr_buff);
  633.   curr_keylength=k_length+nod_flag;
  634.   info->page_changed=1;
  635.   if ((father_key_pos != father_buff+father_length && (info->s->rnd++ & 1)) ||
  636.       father_key_pos == father_buff+2+info->s->base.key_reflength)
  637.   {
  638.     right=1;
  639.     next_page= _nisam_kpos(info->s->base.key_reflength,
  640. father_key_pos+father_keylength);
  641.     buff=info->buff;
  642.     DBUG_PRINT("test",("use right page: %lu",next_page));
  643.   }
  644.   else
  645.   {
  646.     right=0;
  647.     father_key_pos-=father_keylength;
  648.     next_page= _nisam_kpos(info->s->base.key_reflength,father_key_pos);
  649. /* Fix that curr_buff is to left */
  650.     buff=curr_buff; curr_buff=info->buff;
  651.     DBUG_PRINT("test",("use left page: %lu",next_page));
  652.   } /* father_key_pos ptr to parting key */
  653.   if (!_nisam_fetch_keypage(info,keyinfo,next_page,info->buff,0))
  654.     goto err;
  655.   DBUG_DUMP("next",(byte*) info->buff,getint(info->buff));
  656. /* Test if there is room to share keys */
  657.   left_length=getint(curr_buff);
  658.   right_length=getint(buff);
  659.   keys=(left_length+right_length-4-nod_flag*2)/curr_keylength;
  660.   if ((right ? right_length : left_length) + curr_keylength <=
  661.       keyinfo->base.block_length)
  662.   { /* Merge buffs */
  663.     new_left_length=2+nod_flag+(keys/2)*curr_keylength;
  664.     new_right_length=2+nod_flag+((keys+1)/2)*curr_keylength;
  665.     putint(curr_buff,new_left_length,nod_flag);
  666.     putint(buff,new_right_length,nod_flag);
  667.     if (left_length < new_left_length)
  668.     { /* Move keys buff -> leaf */
  669.       pos=curr_buff+left_length;
  670.       memcpy((byte*) pos,(byte*) father_key_pos, (size_t) k_length);
  671.       memcpy((byte*) pos+k_length, (byte*) buff+2,
  672.      (size_t) (length=new_left_length - left_length - k_length));
  673.       pos=buff+2+length;
  674.       memcpy((byte*) father_key_pos,(byte*) pos,(size_t) k_length);
  675.       bmove((byte*) buff+2,(byte*) pos+k_length,new_right_length);
  676.     }
  677.     else
  678.     { /* Move keys -> buff */
  679.       bmove_upp((byte*) buff+new_right_length,(byte*) buff+right_length,
  680. right_length-2);
  681.       length=new_right_length-right_length-k_length;
  682.       memcpy((byte*) buff+2+length,father_key_pos,(size_t) k_length);
  683.       pos=curr_buff+new_left_length;
  684.       memcpy((byte*) father_key_pos,(byte*) pos,(size_t) k_length);
  685.       memcpy((byte*) buff+2,(byte*) pos+k_length,(size_t) length);
  686.     }
  687.     if (_nisam_write_keypage(info,keyinfo,next_page,info->buff) ||
  688. _nisam_write_keypage(info,keyinfo,father_page,father_buff))
  689.       goto err;
  690.     DBUG_RETURN(0);
  691.   }
  692. /* curr_buff[] and buff[] are full, lets splitt and make new nod */
  693.   extra_buff=info->buff+info->s->base.max_block;
  694.   new_left_length=new_right_length=2+nod_flag+(keys+1)/3*curr_keylength;
  695.   if (keys == 5) /* Too few keys to balance */
  696.     new_left_length-=curr_keylength;
  697.   extra_length=nod_flag+left_length+right_length-new_left_length-new_right_length-curr_keylength;
  698.   DBUG_PRINT("info",("left_length: %d  right_length: %d  new_left_length: %d  new_right_length: %d  extra_length: %d",
  699.      left_length, right_length,
  700.      new_left_length, new_right_length,
  701.      extra_length));
  702.   putint(curr_buff,new_left_length,nod_flag);
  703.   putint(buff,new_right_length,nod_flag);
  704.   putint(extra_buff,extra_length+2,nod_flag);
  705.   /* move first largest keys to new page  */
  706.   pos=buff+right_length-extra_length;
  707.   memcpy((byte*) extra_buff+2,pos,(size_t) extra_length);
  708.   /* Save new parting key */
  709.   memcpy(tmp_part_key, pos-k_length,k_length);
  710.   /* Make place for new keys */
  711.   bmove_upp((byte*) buff+new_right_length,(byte*) pos-k_length,
  712.     right_length-extra_length-k_length-2);
  713.   /* Copy keys from left page */
  714.   pos= curr_buff+new_left_length;
  715.   memcpy((byte*) buff+2,(byte*) pos+k_length,
  716.  (size_t) (length=left_length-new_left_length-k_length));
  717.   /* Copy old parting key */
  718.   memcpy((byte*) buff+2+length,father_key_pos,(size_t) k_length);
  719.   /* Move new parting keys up */
  720.   memcpy((byte*) (right ? key : father_key_pos),pos, (size_t) k_length);
  721.   memcpy((byte*) (right ? father_key_pos : key), tmp_part_key, k_length);
  722.   if ((new_pos=_nisam_new(info,keyinfo)) == NI_POS_ERROR)
  723.     goto err;
  724.   _nisam_kpointer(info,key+k_length,new_pos);
  725.   if (_nisam_write_keypage(info,keyinfo,(right ? new_pos : next_page),
  726. info->buff) ||
  727.       _nisam_write_keypage(info,keyinfo,(right ? next_page : new_pos),extra_buff))
  728.     goto err;
  729.   DBUG_RETURN(1); /* Middle key up */
  730. err:
  731.   DBUG_RETURN(-1);
  732. } /* _nisam_balance_page */