~mysql/mysql-server/mysql-6.0

« back to all changes in this revision

Viewing changes to isam/delete.c

  • Committer: bk at mysql
  • Date: 2000-07-31 19:29:14 UTC
  • Revision ID: sp1r-bk@work.mysql.com-20000731192914-08846
Import changeset

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
17
/* Tar bort ett record fr}n en isam-databas */
 
18
 
 
19
#include "isamdef.h"
 
20
#ifdef  __WIN__
 
21
#include <errno.h>
 
22
#endif
 
23
#include <assert.h>
 
24
 
 
25
static int d_search(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,ulong page,
 
26
                    uchar *anc_buff);
 
27
static int del(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,uchar *anc_buff,
 
28
               ulong leaf_page,uchar *leaf_buff,uchar *keypos,
 
29
               ulong next_block,uchar *ret_key);
 
30
static int underflow(N_INFO *info,N_KEYDEF *keyinfo,uchar *anc_buff,
 
31
                     ulong leaf_page, uchar *leaf_buff,uchar *keypos);
 
32
static uint remove_key(N_KEYDEF *keyinfo,uint nod_flag,uchar *keypos,
 
33
                       uchar *lastkey,uchar *page_end);
 
34
 
 
35
 
 
36
int nisam_delete(N_INFO *info,const byte *record)
 
37
{
 
38
  uint i;
 
39
  uchar *old_key;
 
40
  int save_errno;
 
41
  uint32 lastpos;
 
42
  ISAM_SHARE *share=info->s;
 
43
  DBUG_ENTER("nisam_delete");
 
44
 
 
45
        /* Test if record is in datafile */
 
46
 
 
47
  if (!(info->update & HA_STATE_AKTIV))
 
48
  {
 
49
    my_errno=HA_ERR_KEY_NOT_FOUND;              /* No database read */
 
50
    DBUG_RETURN(-1);
 
51
  }
 
52
  if (share->base.options & HA_OPTION_READ_ONLY_DATA)
 
53
  {
 
54
    my_errno=EACCES;
 
55
    DBUG_RETURN(-1);
 
56
  }
 
57
#ifndef NO_LOCKING
 
58
  if (_nisam_readinfo(info,F_WRLCK,1)) DBUG_RETURN(-1);
 
59
#endif
 
60
  if ((*share->compare_record)(info,record))
 
61
    goto err;                           /* Fel vid kontroll-l{sning */
 
62
 
 
63
        /* Remove all keys from the .ISAM file */
 
64
 
 
65
  old_key=info->lastkey+share->base.max_key_length;
 
66
  for (i=0 ; i < share->state.keys ; i++ )
 
67
  {
 
68
    VOID(_nisam_make_key(info,i,old_key,record,info->lastpos));
 
69
    if (_nisam_ck_delete(info,i,old_key)) goto err;
 
70
  }
 
71
 
 
72
  if ((*share->delete_record)(info))
 
73
    goto err;                           /* Remove record from database */
 
74
 
 
75
  info->update= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_DELETED;
 
76
  share->state.records--;
 
77
 
 
78
  lastpos= (uint32) info->lastpos;
 
79
  nisam_log_command(LOG_DELETE,info,(byte*) &lastpos,sizeof(lastpos),0);
 
80
  VOID(_nisam_writeinfo(info,1));
 
81
  allow_break();                        /* Allow SIGHUP & SIGINT */
 
82
  DBUG_RETURN(0);
 
83
 
 
84
err:
 
85
  save_errno=my_errno;
 
86
  lastpos= (uint32) info->lastpos;
 
87
  nisam_log_command(LOG_DELETE,info,(byte*) &lastpos, sizeof(lastpos),0);
 
88
  VOID(_nisam_writeinfo(info,1));
 
89
  info->update|=HA_STATE_WRITTEN;       /* Buffer changed */
 
90
  allow_break();                        /* Allow SIGHUP & SIGINT */
 
91
  my_errno=save_errno;
 
92
  if (save_errno == HA_ERR_KEY_NOT_FOUND)
 
93
    my_errno=HA_ERR_CRASHED;
 
94
 
 
95
  DBUG_RETURN(-1);
 
96
} /* nisam_delete */
 
97
 
 
98
 
 
99
        /* Tar bort en nyckel till isam-nyckelfilen */
 
100
 
 
101
int _nisam_ck_delete(register N_INFO *info, uint keynr, uchar *key)
 
102
{
 
103
  int error;
 
104
  uint nod_flag;
 
105
  ulong old_root;
 
106
  uchar *root_buff;
 
107
  N_KEYDEF *keyinfo;
 
108
  DBUG_ENTER("_nisam_ck_delete");
 
109
 
 
110
  if ((old_root=info->s->state.key_root[keynr]) == NI_POS_ERROR)
 
111
  {
 
112
    my_errno=HA_ERR_CRASHED;
 
113
    DBUG_RETURN(-1);
 
114
  }
 
115
  keyinfo=info->s->keyinfo+keynr;
 
116
  if (!(root_buff= (uchar*) my_alloca((uint) keyinfo->base.block_length+
 
117
                                      N_MAX_KEY_BUFF*2)))
 
118
    DBUG_RETURN(-1);
 
119
  if (!_nisam_fetch_keypage(info,keyinfo,old_root,root_buff,0))
 
120
  {
 
121
    error= -1;
 
122
    goto err;
 
123
  }
 
124
  if ((error=d_search(info,keyinfo,key,old_root,root_buff)) >0)
 
125
  {
 
126
    if (error == 2)
 
127
    {
 
128
      DBUG_PRINT("test",("Enlarging of root when deleting"));
 
129
      error=_nisam_enlarge_root(info,keynr,key);
 
130
    }
 
131
    else
 
132
    {
 
133
      error=0;
 
134
      if (getint(root_buff) <= (nod_flag=test_if_nod(root_buff))+3)
 
135
      {
 
136
        if (nod_flag)
 
137
          info->s->state.key_root[keynr]=_nisam_kpos(nod_flag,
 
138
                                               root_buff+2+nod_flag);
 
139
        else
 
140
          info->s->state.key_root[keynr]= NI_POS_ERROR;
 
141
        if (_nisam_dispose(info,keyinfo,old_root))
 
142
          error= -1;
 
143
      }
 
144
    }
 
145
  }
 
146
err:
 
147
  my_afree((gptr) root_buff);
 
148
  DBUG_RETURN(error);
 
149
} /* _nisam_ck_delete */
 
150
 
 
151
 
 
152
        /* Tar bort en nyckel under root */
 
153
        /* Returnerar 1 om nuvarande buffert minskade */
 
154
        /* Returnerar 2 om nuvarande buffert |kar */
 
155
 
 
156
static int d_search(register N_INFO *info, register N_KEYDEF *keyinfo, uchar *key, ulong page, uchar *anc_buff)
 
157
{
 
158
  int flag,ret_value,save_flag;
 
159
  uint length,nod_flag;
 
160
  uchar *leaf_buff,*keypos,*next_keypos;
 
161
  ulong leaf_page,next_block;
 
162
  uchar lastkey[N_MAX_KEY_BUFF];
 
163
  DBUG_ENTER("d_search");
 
164
  DBUG_DUMP("page",(byte*) anc_buff,getint(anc_buff));
 
165
 
 
166
  flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key,0,SEARCH_SAME,&keypos,
 
167
                              lastkey);
 
168
  nod_flag=test_if_nod(anc_buff);
 
169
 
 
170
  leaf_buff=0;
 
171
  LINT_INIT(leaf_page);
 
172
  if (nod_flag)
 
173
  {
 
174
    leaf_page=_nisam_kpos(nod_flag,keypos);
 
175
    if (!(leaf_buff= (uchar*) my_alloca((uint) keyinfo->base.block_length+
 
176
                                        N_MAX_KEY_BUFF*2)))
 
177
    {
 
178
      my_errno=ENOMEM;
 
179
      DBUG_RETURN(-1);
 
180
    }
 
181
    if (!_nisam_fetch_keypage(info,keyinfo,leaf_page,leaf_buff,0))
 
182
      goto err;
 
183
  }
 
184
 
 
185
  if (flag != 0)
 
186
  {
 
187
    if (!nod_flag)
 
188
    {
 
189
      my_errno=HA_ERR_CRASHED;          /* This should newer happend */
 
190
      goto err;
 
191
    }
 
192
    save_flag=0;
 
193
    ret_value=d_search(info,keyinfo,key,leaf_page,leaf_buff);
 
194
  }
 
195
  else
 
196
  {                                             /* Found key */
 
197
    next_keypos=keypos;                         /* Find where next block is */
 
198
    VOID((*keyinfo->get_key)(keyinfo,nod_flag,&next_keypos,lastkey));
 
199
    next_block=_nisam_kpos(nod_flag,next_keypos);
 
200
    length=getint(anc_buff);
 
201
    length-= remove_key(keyinfo,nod_flag,keypos,lastkey,anc_buff+length);
 
202
    putint(anc_buff,length,nod_flag);
 
203
    if (!nod_flag)
 
204
    {                                           /* On leaf page */
 
205
      if (_nisam_write_keypage(info,keyinfo,page,anc_buff))
 
206
        DBUG_RETURN(-1);
 
207
      DBUG_RETURN(length <= (uint) keyinfo->base.block_length/2);
 
208
    }
 
209
    save_flag=1;
 
210
    ret_value=del(info,keyinfo,key,anc_buff,leaf_page,leaf_buff,keypos,
 
211
                  next_block,lastkey);
 
212
  }
 
213
  if (ret_value >0)
 
214
  {
 
215
    save_flag=1;
 
216
    if (ret_value == 1)
 
217
      ret_value= underflow(info,keyinfo,anc_buff,leaf_page,leaf_buff,keypos);
 
218
    else
 
219
    {                           /* This happens only with packed keys */
 
220
      DBUG_PRINT("test",("Enlarging of key when deleting"));
 
221
      VOID(_nisam_get_last_key(info,keyinfo,anc_buff,lastkey,keypos));
 
222
      ret_value=_nisam_insert(info,keyinfo,key,anc_buff,keypos,lastkey,
 
223
                           (uchar*) 0,(uchar*) 0,0L);
 
224
    }
 
225
  }
 
226
  if (ret_value == 0 && getint(anc_buff) > keyinfo->base.block_length)
 
227
  {
 
228
    save_flag=1;
 
229
    ret_value=_nisam_splitt_page(info,keyinfo,key,anc_buff,lastkey) | 2;
 
230
  }
 
231
  if (save_flag)
 
232
    ret_value|=_nisam_write_keypage(info,keyinfo,page,anc_buff);
 
233
  else
 
234
  {
 
235
    DBUG_DUMP("page",(byte*) anc_buff,getint(anc_buff));
 
236
  }
 
237
  my_afree((byte*) leaf_buff);
 
238
  DBUG_RETURN(ret_value);
 
239
err:
 
240
  my_afree((byte*) leaf_buff);
 
241
  DBUG_PRINT("exit",("Error: %d",my_errno));
 
242
  DBUG_RETURN (-1);
 
243
} /* d_search */
 
244
 
 
245
 
 
246
        /* Remove a key that has a page-reference */
 
247
 
 
248
static int del(register N_INFO *info, register N_KEYDEF *keyinfo, uchar *key,
 
249
               uchar *anc_buff, ulong leaf_page, uchar *leaf_buff,
 
250
               uchar *keypos,           /* Pos to where deleted key was */
 
251
               ulong next_block,
 
252
               uchar *ret_key)          /* key before keypos in anc_buff */
 
253
{
 
254
  int ret_value,length;
 
255
  uint a_length,nod_flag;
 
256
  ulong next_page;
 
257
  uchar keybuff[N_MAX_KEY_BUFF],*endpos,*next_buff,*key_start;
 
258
  ISAM_SHARE *share=info->s;
 
259
  S_PARAM s_temp;
 
260
  DBUG_ENTER("del");
 
261
  DBUG_PRINT("enter",("leaf_page: %ld   keypos: %lx",leaf_page,keypos));
 
262
  DBUG_DUMP("leaf_buff",(byte*) leaf_buff,getint(leaf_buff));
 
263
 
 
264
  endpos=leaf_buff+getint(leaf_buff);
 
265
  key_start=_nisam_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos);
 
266
 
 
267
  if ((nod_flag=test_if_nod(leaf_buff)))
 
268
  {
 
269
    next_page= _nisam_kpos(nod_flag,endpos);
 
270
    if (!(next_buff= (uchar*) my_alloca((uint) keyinfo->base.block_length+
 
271
                                        N_MAX_KEY_BUFF)))
 
272
      DBUG_RETURN(-1);
 
273
    if (!_nisam_fetch_keypage(info,keyinfo,next_page,next_buff,0))
 
274
      ret_value= -1;
 
275
    else
 
276
    {
 
277
      DBUG_DUMP("next_page",(byte*) next_buff,getint(next_buff));
 
278
      if ((ret_value=del(info,keyinfo,key,anc_buff,next_page,next_buff,
 
279
                         keypos,next_block,ret_key)) >0)
 
280
      {
 
281
        endpos=leaf_buff+getint(leaf_buff);
 
282
        if (ret_value == 1)
 
283
        {
 
284
          ret_value=underflow(info,keyinfo,leaf_buff,next_page,
 
285
                              next_buff,endpos);
 
286
          if (ret_value == 0 && getint(leaf_buff) > keyinfo->base.block_length)
 
287
          {
 
288
            ret_value=_nisam_splitt_page(info,keyinfo,key,leaf_buff,ret_key) | 2;
 
289
          }
 
290
        }
 
291
        else
 
292
        {
 
293
          DBUG_PRINT("test",("Inserting of key when deleting"));
 
294
          VOID(_nisam_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos));
 
295
          ret_value=_nisam_insert(info,keyinfo,key,leaf_buff,endpos,keybuff,
 
296
                               (uchar*) 0,(uchar*) 0,0L);
 
297
        }
 
298
      }
 
299
      if (_nisam_write_keypage(info,keyinfo,leaf_page,leaf_buff))
 
300
        goto err;
 
301
    }
 
302
    my_afree((byte*) next_buff);
 
303
    DBUG_RETURN(ret_value);
 
304
  }
 
305
 
 
306
        /* Remove last key from leaf page */
 
307
 
 
308
  putint(leaf_buff,key_start-leaf_buff,nod_flag);
 
309
  if (_nisam_write_keypage(info,keyinfo,leaf_page,leaf_buff))
 
310
    goto err;
 
311
 
 
312
        /* Place last key in ancestor page on deleted key position */
 
313
 
 
314
  a_length=getint(anc_buff);
 
315
  endpos=anc_buff+a_length;
 
316
  VOID(_nisam_get_last_key(info,keyinfo,anc_buff,ret_key,keypos));
 
317
  length=_nisam_get_pack_key_length(keyinfo,share->base.key_reflength,
 
318
                                 keypos == endpos ? (uchar*) 0 : keypos,
 
319
                                 ret_key,keybuff,&s_temp);
 
320
  if (length > 0)
 
321
    bmove_upp((byte*) endpos+length,(byte*) endpos,(uint) (endpos-keypos));
 
322
  else
 
323
    bmove(keypos,keypos-length, (int) (endpos-keypos)+length);
 
324
  _nisam_store_key(keyinfo,keypos,&s_temp);
 
325
        /* Save pointer to next leaf */
 
326
  VOID((*keyinfo->get_key)(keyinfo,share->base.key_reflength,&keypos,ret_key));
 
327
  _nisam_kpointer(info,keypos - share->base.key_reflength,next_block);
 
328
  putint(anc_buff,a_length+length,share->base.key_reflength);
 
329
 
 
330
  DBUG_RETURN( getint(leaf_buff) <= (uint) keyinfo->base.block_length/2 );
 
331
err:
 
332
  DBUG_RETURN(-1);
 
333
} /* del */
 
334
 
 
335
 
 
336
        /* Balances adjacent pages if underflow occours */
 
337
 
 
338
static int underflow(register N_INFO *info, register N_KEYDEF *keyinfo,
 
339
                     uchar *anc_buff,
 
340
                     ulong leaf_page,   /* Ancestor page and underflow page */
 
341
                     uchar *leaf_buff,
 
342
                     uchar *keypos)     /* Position to pos after key */
 
343
{
 
344
  int t_length;
 
345
  uint length,anc_length,buff_length,leaf_length,p_length,s_length,nod_flag;
 
346
  ulong next_page;
 
347
  uchar anc_key[N_MAX_KEY_BUFF],leaf_key[N_MAX_KEY_BUFF],
 
348
        *buff,*endpos,*next_keypos,*half_pos,*temp_pos;
 
349
  S_PARAM s_temp;
 
350
  ISAM_SHARE *share=info->s;
 
351
  DBUG_ENTER("underflow");
 
352
  DBUG_PRINT("enter",("leaf_page: %ld   keypos: %lx",leaf_page,keypos));
 
353
  DBUG_DUMP("anc_buff",(byte*) anc_buff,getint(anc_buff));
 
354
  DBUG_DUMP("leaf_buff",(byte*) leaf_buff,getint(leaf_buff));
 
355
 
 
356
  buff=info->buff;
 
357
  next_keypos=keypos;
 
358
  nod_flag=test_if_nod(leaf_buff);
 
359
  p_length=2+nod_flag;
 
360
  anc_length=getint(anc_buff);
 
361
  leaf_length=getint(leaf_buff);
 
362
  info->page_changed=1;
 
363
 
 
364
  if ((keypos < anc_buff+anc_length && (share->rnd++ & 1)) ||
 
365
      keypos == anc_buff+2+share->base.key_reflength)
 
366
  {                                     /* Use page right of anc-page */
 
367
    DBUG_PRINT("test",("use right page"));
 
368
 
 
369
    VOID((*keyinfo->get_key)(keyinfo,share->base.key_reflength,&next_keypos,
 
370
                             buff));
 
371
    next_page= _nisam_kpos(share->base.key_reflength,next_keypos);
 
372
    if (!_nisam_fetch_keypage(info,keyinfo,next_page,buff,0))
 
373
      goto err;
 
374
    buff_length=getint(buff);
 
375
    DBUG_DUMP("next",(byte*) buff,buff_length);
 
376
 
 
377
    /* find keys to make a big key-page */
 
378
    bmove((byte*) next_keypos-share->base.key_reflength,(byte*) buff+2,
 
379
          share->base.key_reflength);
 
380
    VOID(_nisam_get_last_key(info,keyinfo,anc_buff,anc_key,next_keypos));
 
381
    VOID(_nisam_get_last_key(info,keyinfo,leaf_buff,leaf_key,
 
382
                          leaf_buff+leaf_length));
 
383
 
 
384
    /* merge pages and put parting key from anc_buff between */
 
385
    t_length=(int) _nisam_get_pack_key_length(keyinfo,nod_flag,buff+p_length,
 
386
                                           (leaf_length == nod_flag+2 ?
 
387
                                            (uchar*) 0 : leaf_key),
 
388
                                           anc_key,&s_temp);
 
389
    length=buff_length-p_length;
 
390
    endpos=buff+length+leaf_length+t_length;
 
391
    bmove_upp((byte*) endpos, (byte*) buff+buff_length,length);
 
392
    memcpy((byte*) buff, (byte*) leaf_buff,(size_t) leaf_length);
 
393
    _nisam_store_key(keyinfo,buff+leaf_length,&s_temp);
 
394
    buff_length=(uint) (endpos-buff);
 
395
    putint(buff,buff_length,nod_flag);
 
396
 
 
397
    /* remove key from anc_buff */
 
398
 
 
399
    s_length=remove_key(keyinfo,share->base.key_reflength,keypos,anc_key,
 
400
                        anc_buff+anc_length);
 
401
    putint(anc_buff,(anc_length-=s_length),share->base.key_reflength);
 
402
 
 
403
    if (buff_length <= keyinfo->base.block_length)
 
404
    {                                           /* Keys in one page */
 
405
      memcpy((byte*) leaf_buff,(byte*) buff,(size_t) buff_length);
 
406
      if (_nisam_dispose(info,keyinfo,next_page))
 
407
       goto err;
 
408
    }
 
409
    else
 
410
    {                                           /* Page is full */
 
411
      VOID(_nisam_get_last_key(info,keyinfo,anc_buff,anc_key,keypos));
 
412
      half_pos=_nisam_find_half_pos(info,keyinfo,buff,leaf_key);
 
413
      length=(uint) (half_pos-buff);
 
414
      memcpy((byte*) leaf_buff,(byte*) buff,(size_t) length);
 
415
      putint(leaf_buff,length,nod_flag);
 
416
      endpos=anc_buff+anc_length;
 
417
 
 
418
      /* Correct new keypointer to leaf_page */
 
419
      length=(*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key);
 
420
      _nisam_kpointer(info,leaf_key+length,next_page);
 
421
      /* Save key in anc_buff */
 
422
      t_length=(int) _nisam_get_pack_key_length(keyinfo,
 
423
                                                share->base.key_reflength,
 
424
                                                keypos == endpos ?
 
425
                                                (uchar*) 0 : keypos,
 
426
                                                anc_key,leaf_key,&s_temp);
 
427
      if (t_length >= 0)
 
428
        bmove_upp((byte*) endpos+t_length,(byte*) endpos,
 
429
                  (uint) (endpos-keypos));
 
430
      else
 
431
        bmove(keypos,keypos-t_length,(uint) (endpos-keypos)+t_length);
 
432
      _nisam_store_key(keyinfo,keypos,&s_temp);
 
433
      putint(anc_buff,(anc_length+=t_length),share->base.key_reflength);
 
434
 
 
435
        /* Store new page */
 
436
      if (nod_flag)
 
437
        bmove((byte*) buff+2,(byte*) half_pos-nod_flag,(size_t) nod_flag);
 
438
      VOID((*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key));
 
439
      t_length=(int) _nisam_get_pack_key_length(keyinfo,nod_flag,(uchar*) 0,
 
440
                                             (uchar*) 0, leaf_key,&s_temp);
 
441
      s_temp.n_length= *half_pos;       /* For _nisam_store_key */
 
442
      length=(buff+getint(buff))-half_pos;
 
443
      bmove((byte*) buff+p_length+t_length,(byte*) half_pos,(size_t) length);
 
444
      _nisam_store_key(keyinfo,buff+p_length,&s_temp);
 
445
      putint(buff,length+t_length+p_length,nod_flag);
 
446
 
 
447
      if (_nisam_write_keypage(info,keyinfo,next_page,buff))
 
448
        goto err;
 
449
    }
 
450
    if (_nisam_write_keypage(info,keyinfo,leaf_page,leaf_buff))
 
451
      goto err;
 
452
    DBUG_RETURN(anc_length <= (uint) keyinfo->base.block_length/2);
 
453
  }
 
454
 
 
455
  DBUG_PRINT("test",("use left page"));
 
456
 
 
457
  keypos=_nisam_get_last_key(info,keyinfo,anc_buff,anc_key,keypos);
 
458
  next_page= _nisam_kpos(share->base.key_reflength,keypos);
 
459
  if (!_nisam_fetch_keypage(info,keyinfo,next_page,buff,0))
 
460
      goto err;
 
461
  buff_length=getint(buff);
 
462
  endpos=buff+buff_length;
 
463
  DBUG_DUMP("prev",(byte*) buff,buff_length);
 
464
 
 
465
  /* find keys to make a big key-page */
 
466
  bmove((byte*) next_keypos - share->base.key_reflength,(byte*) leaf_buff+2,
 
467
        share->base.key_reflength);
 
468
  next_keypos=keypos;
 
469
  VOID((*keyinfo->get_key)(keyinfo,share->base.key_reflength,&next_keypos,
 
470
                           anc_key));
 
471
  VOID(_nisam_get_last_key(info,keyinfo,buff,leaf_key,endpos));
 
472
 
 
473
  /* merge pages and put parting key from anc_buff between */
 
474
  t_length=(int) _nisam_get_pack_key_length(keyinfo,nod_flag,
 
475
                                            leaf_buff+p_length,
 
476
                                            (leaf_length == nod_flag+2 ?
 
477
                                             (uchar*) 0 : leaf_key),
 
478
                                            anc_key,&s_temp);
 
479
  if (t_length >= 0)
 
480
    bmove((byte*) endpos+t_length,(byte*) leaf_buff+p_length,
 
481
            (size_t) (leaf_length-p_length));
 
482
  else                                          /* We gained space */
 
483
    bmove((byte*) endpos,(byte*) leaf_buff+((int) p_length-t_length),
 
484
            (size_t) (leaf_length-p_length+t_length));
 
485
 
 
486
  _nisam_store_key(keyinfo,endpos,&s_temp);
 
487
  buff_length=buff_length+leaf_length-p_length+t_length;
 
488
  putint(buff,buff_length,nod_flag);
 
489
 
 
490
  /* remove key from anc_buff */
 
491
  s_length=remove_key(keyinfo,share->base.key_reflength,keypos,anc_key,
 
492
                      anc_buff+anc_length);
 
493
  putint(anc_buff,(anc_length-=s_length),share->base.key_reflength);
 
494
 
 
495
  if (buff_length <= keyinfo->base.block_length)
 
496
  {                                             /* Keys in one page */
 
497
    if (_nisam_dispose(info,keyinfo,leaf_page))
 
498
      goto err;
 
499
  }
 
500
  else
 
501
  {                                             /* Page is full */
 
502
    VOID(_nisam_get_last_key(info,keyinfo,anc_buff,anc_key,keypos));
 
503
    endpos=half_pos=_nisam_find_half_pos(info,keyinfo,buff,leaf_key);
 
504
 
 
505
    /* Correct new keypointer to leaf_page */
 
506
    length=(*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key);
 
507
    _nisam_kpointer(info,leaf_key+length,leaf_page);
 
508
    /* Save key in anc_buff */
 
509
    DBUG_DUMP("anc_buff",(byte*) anc_buff,anc_length);
 
510
    DBUG_DUMP("key",(byte*) leaf_key,16);
 
511
 
 
512
    temp_pos=anc_buff+anc_length;
 
513
    t_length=(int) _nisam_get_pack_key_length(keyinfo,
 
514
                                              share->base.key_reflength,
 
515
                                              keypos == temp_pos ? (uchar*) 0
 
516
                                              : keypos,
 
517
                                              anc_key,leaf_key,&s_temp);
 
518
    if (t_length > 0)
 
519
      bmove_upp((byte*) temp_pos+t_length,(byte*) temp_pos,
 
520
                (uint) (temp_pos-keypos));
 
521
    else
 
522
      bmove(keypos,keypos-t_length,(uint) (temp_pos-keypos)+t_length);
 
523
    _nisam_store_key(keyinfo,keypos,&s_temp);
 
524
    putint(anc_buff,(anc_length+=t_length),share->base.key_reflength);
 
525
 
 
526
    /* Store new page */
 
527
    if (nod_flag)
 
528
      bmove((byte*) leaf_buff+2,(byte*) half_pos-nod_flag,(size_t) nod_flag);
 
529
    VOID((*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key));
 
530
    t_length=(int) _nisam_get_pack_key_length(keyinfo,nod_flag, (uchar*) 0,
 
531
                                           (uchar*) 0, leaf_key, &s_temp);
 
532
    s_temp.n_length= *half_pos;         /* For _nisam_store_key */
 
533
    length=(uint) ((buff+buff_length)-half_pos);
 
534
    bmove((byte*) leaf_buff+p_length+t_length,(byte*) half_pos,
 
535
            (size_t) length);
 
536
    _nisam_store_key(keyinfo,leaf_buff+p_length,&s_temp);
 
537
    putint(leaf_buff,length+t_length+p_length,nod_flag);
 
538
    putint(buff,endpos-buff,nod_flag);
 
539
    if (_nisam_write_keypage(info,keyinfo,leaf_page,leaf_buff))
 
540
        goto err;
 
541
  }
 
542
  if (_nisam_write_keypage(info,keyinfo,next_page,buff))
 
543
    goto err;
 
544
  DBUG_RETURN(anc_length <= (uint) keyinfo->base.block_length/2);
 
545
err:
 
546
  DBUG_RETURN(-1);
 
547
} /* underflow */
 
548
 
 
549
 
 
550
        /* remove a key from packed buffert */
 
551
        /* returns how many chars was removed */
 
552
 
 
553
static uint remove_key(N_KEYDEF *keyinfo, uint nod_flag,
 
554
                       uchar *keypos,   /* Where key starts */
 
555
                       uchar *lastkey,  /* key to be removed */
 
556
                       uchar *page_end) /* End of page */
 
557
{
 
558
  int r_length,s_length,first,diff_flag;
 
559
  uchar *start;
 
560
  DBUG_ENTER("remove_key");
 
561
  DBUG_PRINT("enter",("keypos: %lx  page_end: %lx",keypos,page_end));
 
562
 
 
563
  start=keypos;
 
564
  if (!(keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED)))
 
565
    s_length=(int) (keyinfo->base.keylength+nod_flag);
 
566
  else
 
567
  {                                      /* Let keypos point at next key */
 
568
    VOID((*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey));
 
569
    s_length=(keypos-start);
 
570
    if (keyinfo->base.flag & HA_PACK_KEY)
 
571
    {
 
572
      diff_flag= (keyinfo->seg[0].base.flag & HA_SPACE_PACK);
 
573
      first= *start;
 
574
      if (keypos != page_end && *keypos & 128 && first != 128)
 
575
      {                                 /* Referens length */
 
576
        if ((r_length= *keypos++ & 127) == 0)
 
577
        {                               /* Same key after */
 
578
          if (first & 128)
 
579
            start++;                    /* Skipp ref length */
 
580
          if (diff_flag)
 
581
            start+= *start+1;           /* Skipp key length */
 
582
          else
 
583
            start+=keyinfo->seg[0].base.length- (first & 127);
 
584
          s_length=(keypos-start);      /* Remove pointers and next-key-flag */
 
585
        }
 
586
        else if (! (first & 128))
 
587
        {                               /* Deleted key was not compressed */
 
588
          if (diff_flag)
 
589
          {
 
590
            *start= (uchar) (r_length+ *keypos);
 
591
            start+=r_length+1;          /* Let ref-part remain */
 
592
            s_length=(keypos-start)+1;  /* Skipp everything between */
 
593
          }
 
594
          else
 
595
          {
 
596
            start+=r_length+1;          /* Let ref-part remain */
 
597
            s_length=(keypos-start);    /* Skipp everything between */
 
598
          }
 
599
        }
 
600
        else if ((first & 127) < r_length)
 
601
        {                               /* mid-part of key is used */
 
602
          r_length-=(first & 127);
 
603
          start++;                      /* Ref remains the same */
 
604
          if (diff_flag)
 
605
            *start++= (uchar) (*keypos++ + r_length);
 
606
          start+= r_length;
 
607
          s_length=(keypos-start);      /* Skipp everything between */
 
608
        }
 
609
      }
 
610
    }
 
611
  }
 
612
  bmove((byte*) start,(byte*) start+s_length,
 
613
        (uint) (page_end-start-s_length));
 
614
  DBUG_RETURN((uint) s_length);
 
615
} /* remove_key */