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

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