2 Copyright (c) 2000-2008 MySQL AB, 2008, 2009 Sun Microsystems, Inc.
3 Use is subject to license terms.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 /* Remove a row from a MyISAM table */
24 static int d_search(MI_INFO
*info
,MI_KEYDEF
*keyinfo
,uint comp_flag
,
25 uchar
*key
,uint key_length
,my_off_t page
,uchar
*anc_buff
);
26 static int del(MI_INFO
*info
,MI_KEYDEF
*keyinfo
,uchar
*key
,uchar
*anc_buff
,
27 my_off_t leaf_page
,uchar
*leaf_buff
,uchar
*keypos
,
28 my_off_t next_block
,uchar
*ret_key
);
29 static int underflow(MI_INFO
*info
,MI_KEYDEF
*keyinfo
,uchar
*anc_buff
,
30 my_off_t leaf_page
,uchar
*leaf_buff
,uchar
*keypos
);
31 static uint
remove_key(MI_KEYDEF
*keyinfo
,uint nod_flag
,uchar
*keypos
,
32 uchar
*lastkey
,uchar
*page_end
,
33 my_off_t
*next_block
);
34 static int _mi_ck_real_delete(register MI_INFO
*info
,MI_KEYDEF
*keyinfo
,
35 uchar
*key
, uint key_length
, my_off_t
*root
);
38 int mi_delete(MI_INFO
*info
,const uchar
*record
)
45 MYISAM_SHARE
*share
=info
->s
;
46 DBUG_ENTER("mi_delete");
48 /* Test if record is in datafile */
50 DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage",
51 mi_print_error(info
->s
, HA_ERR_CRASHED
);
52 DBUG_RETURN(my_errno
= HA_ERR_CRASHED
););
53 DBUG_EXECUTE_IF("my_error_test_undefined_error",
54 mi_print_error(info
->s
, INT_MAX
);
55 DBUG_RETURN(my_errno
= INT_MAX
););
56 if (!(info
->update
& HA_STATE_AKTIV
))
58 DBUG_RETURN(my_errno
=HA_ERR_KEY_NOT_FOUND
); /* No database read */
60 if (share
->options
& HA_OPTION_READ_ONLY_DATA
)
62 DBUG_RETURN(my_errno
=EACCES
);
64 if (_mi_readinfo(info
,F_WRLCK
,1))
65 DBUG_RETURN(my_errno
);
66 if (info
->s
->calc_checksum
)
67 info
->checksum
=(*info
->s
->calc_checksum
)(info
,record
);
68 if ((*share
->compare_record
)(info
,record
))
69 goto err
; /* Error on read-check */
71 if (_mi_mark_file_changed(info
))
74 /* Remove all keys from the .ISAM file */
76 old_key
=info
->lastkey2
;
77 for (i
=0 ; i
< share
->base
.keys
; i
++ )
79 if (mi_is_key_active(info
->s
->state
.key_map
, i
))
81 info
->s
->keyinfo
[i
].version
++;
82 if (info
->s
->keyinfo
[i
].flag
& HA_FULLTEXT
)
84 if (_mi_ft_del(info
,i
, old_key
,record
,info
->lastpos
))
89 if (info
->s
->keyinfo
[i
].ck_delete(info
,i
,old_key
,
90 _mi_make_key(info
,i
,old_key
,record
,info
->lastpos
)))
93 /* The above changed info->lastkey2. Inform mi_rnext_same(). */
94 info
->update
&= ~HA_STATE_RNEXT_SAME
;
98 if ((*share
->delete_record
)(info
))
99 goto err
; /* Remove record from database */
100 info
->state
->checksum
-=info
->checksum
;
102 info
->update
= HA_STATE_CHANGED
+HA_STATE_DELETED
+HA_STATE_ROW_CHANGED
;
103 info
->state
->records
--;
105 mi_sizestore(lastpos
,info
->lastpos
);
106 myisam_log_command(MI_LOG_DELETE
,info
,(uchar
*) lastpos
,sizeof(lastpos
),0);
107 VOID(_mi_writeinfo(info
,WRITEINFO_UPDATE_KEYFILE
));
108 allow_break(); /* Allow SIGHUP & SIGINT */
109 if (info
->invalidator
!= 0)
111 DBUG_PRINT("info", ("invalidator... '%s' (delete)", info
->filename
));
112 (*info
->invalidator
)(info
->filename
);
119 mi_sizestore(lastpos
,info
->lastpos
);
120 myisam_log_command(MI_LOG_DELETE
,info
,(uchar
*) lastpos
, sizeof(lastpos
),0);
121 if (save_errno
!= HA_ERR_RECORD_CHANGED
)
123 mi_print_error(info
->s
, HA_ERR_CRASHED
);
124 mi_mark_crashed(info
); /* mark table crashed */
126 VOID(_mi_writeinfo(info
,WRITEINFO_UPDATE_KEYFILE
));
127 info
->update
|=HA_STATE_WRITTEN
; /* Buffer changed */
128 allow_break(); /* Allow SIGHUP & SIGINT */
130 if (save_errno
== HA_ERR_KEY_NOT_FOUND
)
132 mi_print_error(info
->s
, HA_ERR_CRASHED
);
133 my_errno
=HA_ERR_CRASHED
;
136 DBUG_RETURN(my_errno
);
140 /* Remove a key from the btree index */
142 int _mi_ck_delete(register MI_INFO
*info
, uint keynr
, uchar
*key
,
145 return _mi_ck_real_delete(info
, info
->s
->keyinfo
+keynr
, key
, key_length
,
146 &info
->s
->state
.key_root
[keynr
]);
147 } /* _mi_ck_delete */
150 static int _mi_ck_real_delete(register MI_INFO
*info
, MI_KEYDEF
*keyinfo
,
151 uchar
*key
, uint key_length
, my_off_t
*root
)
157 DBUG_ENTER("_mi_ck_real_delete");
159 if ((old_root
=*root
) == HA_OFFSET_ERROR
)
161 mi_print_error(info
->s
, HA_ERR_CRASHED
);
162 DBUG_RETURN(my_errno
=HA_ERR_CRASHED
);
164 if (!(root_buff
= (uchar
*) my_alloca((uint
) keyinfo
->block_length
+
167 DBUG_PRINT("error",("Couldn't allocate memory"));
168 DBUG_RETURN(my_errno
=ENOMEM
);
170 DBUG_PRINT("info",("root_page: %ld", (long) old_root
));
171 if (!_mi_fetch_keypage(info
,keyinfo
,old_root
,DFLT_INIT_HITS
,root_buff
,0))
176 if ((error
=d_search(info
,keyinfo
,
177 (keyinfo
->flag
& HA_FULLTEXT
? SEARCH_FIND
| SEARCH_UPDATE
179 key
,key_length
,old_root
,root_buff
)) >0)
183 DBUG_PRINT("test",("Enlarging of root when deleting"));
184 error
=_mi_enlarge_root(info
,keyinfo
,key
,root
);
186 else /* error == 1 */
188 if (mi_getint(root_buff
) <= (nod_flag
=mi_test_if_nod(root_buff
))+3)
192 *root
=_mi_kpos(nod_flag
,root_buff
+2+nod_flag
);
194 *root
=HA_OFFSET_ERROR
;
195 if (_mi_dispose(info
,keyinfo
,old_root
,DFLT_INIT_HITS
))
199 error
=_mi_write_keypage(info
,keyinfo
,old_root
,
200 DFLT_INIT_HITS
,root_buff
);
204 my_afree((uchar
*) root_buff
);
205 DBUG_PRINT("exit",("Return: %d",error
));
207 } /* _mi_ck_real_delete */
211 ** Remove key below key root
213 ** 1 if there are less buffers; In this case anc_buff is not saved
214 ** 2 if there are more buffers
218 static int d_search(register MI_INFO
*info
, register MI_KEYDEF
*keyinfo
,
219 uint comp_flag
, uchar
*key
, uint key_length
,
220 my_off_t page
, uchar
*anc_buff
)
222 int flag
,ret_value
,save_flag
;
223 uint length
,nod_flag
,search_key_length
;
225 uchar
*leaf_buff
,*keypos
;
226 my_off_t
UNINIT_VAR(leaf_page
),next_block
;
227 uchar lastkey
[MI_MAX_KEY_BUFF
];
228 DBUG_ENTER("d_search");
229 DBUG_DUMP("page",(uchar
*) anc_buff
,mi_getint(anc_buff
));
231 search_key_length
= (comp_flag
& SEARCH_FIND
) ? key_length
: USE_WHOLE_KEY
;
232 flag
=(*keyinfo
->bin_search
)(info
,keyinfo
,anc_buff
,key
, search_key_length
,
233 comp_flag
, &keypos
, lastkey
, &last_key
);
234 if (flag
== MI_FOUND_WRONG_KEY
)
236 DBUG_PRINT("error",("Found wrong key"));
239 nod_flag
=mi_test_if_nod(anc_buff
);
241 if (!flag
&& keyinfo
->flag
& HA_FULLTEXT
)
246 get_key_full_length_rdonly(off
, lastkey
);
247 subkeys
=ft_sintXkorr(lastkey
+off
);
248 DBUG_ASSERT(info
->ft1_to_ft2
==0 || subkeys
>=0);
249 comp_flag
=SEARCH_SAME
;
252 /* normal word, one-level tree structure */
253 if (info
->ft1_to_ft2
)
255 /* we're in ft1->ft2 conversion mode. Saving key data */
256 if (insert_dynamic(info
->ft1_to_ft2
, (lastkey
+off
)))
258 DBUG_PRINT("error",("Out of memory"));
264 /* we need exact match only if not in ft1->ft2 conversion mode */
265 flag
=(*keyinfo
->bin_search
)(info
,keyinfo
,anc_buff
,key
,USE_WHOLE_KEY
,
266 comp_flag
, &keypos
, lastkey
, &last_key
);
268 /* fall through to normal delete */
272 /* popular word. two-level tree. going down */
277 if (!(tmp_key_length
=(*keyinfo
->get_key
)(keyinfo
,nod_flag
,&kpos
,lastkey
)))
279 mi_print_error(info
->s
, HA_ERR_CRASHED
);
280 my_errno
= HA_ERR_CRASHED
;
283 root
=_mi_dpos(info
,nod_flag
,kpos
);
286 /* the last entry in sub-tree */
287 if (_mi_dispose(info
, keyinfo
, root
,DFLT_INIT_HITS
))
289 /* fall through to normal delete */
293 keyinfo
=&info
->s
->ft2_keyinfo
;
294 kpos
-=keyinfo
->keylength
+nod_flag
; /* we'll modify key entry 'in vivo' */
295 get_key_full_length_rdonly(off
, key
);
297 ret_value
=_mi_ck_real_delete(info
, &info
->s
->ft2_keyinfo
,
298 key
, HA_FT_WLEN
, &root
);
299 _mi_dpointer(info
, kpos
+HA_FT_WLEN
, root
);
301 ft_intXstore(kpos
, subkeys
);
303 ret_value
=_mi_write_keypage(info
,keyinfo
,page
,
304 DFLT_INIT_HITS
,anc_buff
);
305 DBUG_PRINT("exit",("Return: %d",ret_value
));
306 DBUG_RETURN(ret_value
);
311 LINT_INIT(leaf_page
);
314 leaf_page
=_mi_kpos(nod_flag
,keypos
);
315 if (!(leaf_buff
= (uchar
*) my_alloca((uint
) keyinfo
->block_length
+
318 DBUG_PRINT("error",("Couldn't allocate memory"));
320 DBUG_PRINT("exit",("Return: %d",-1));
323 if (!_mi_fetch_keypage(info
,keyinfo
,leaf_page
,DFLT_INIT_HITS
,leaf_buff
,0))
331 DBUG_PRINT("error",("Didn't find key"));
332 mi_print_error(info
->s
, HA_ERR_CRASHED
);
333 my_errno
=HA_ERR_CRASHED
; /* This should newer happend */
337 ret_value
=d_search(info
,keyinfo
,comp_flag
,key
,key_length
,
338 leaf_page
,leaf_buff
);
343 length
=mi_getint(anc_buff
);
344 if (!(tmp
= remove_key(keyinfo
,nod_flag
,keypos
,lastkey
,anc_buff
+length
,
350 mi_putint(anc_buff
,length
,nod_flag
);
353 if (_mi_write_keypage(info
,keyinfo
,page
,DFLT_INIT_HITS
,anc_buff
))
355 DBUG_PRINT("exit",("Return: %d",-1));
358 /* Page will be update later if we return 1 */
359 DBUG_RETURN(test(length
<= (info
->quick_mode
? MI_MIN_KEYBLOCK_LENGTH
:
360 (uint
) keyinfo
->underflow_block_length
)));
363 ret_value
=del(info
,keyinfo
,key
,anc_buff
,leaf_page
,leaf_buff
,keypos
,
370 ret_value
= underflow(info
,keyinfo
,anc_buff
,leaf_page
,leaf_buff
,keypos
);
372 { /* This happens only with packed keys */
373 DBUG_PRINT("test",("Enlarging of key when deleting"));
374 if (!_mi_get_last_key(info
,keyinfo
,anc_buff
,lastkey
,keypos
,&length
))
378 ret_value
=_mi_insert(info
,keyinfo
,key
,anc_buff
,keypos
,lastkey
,
379 (uchar
*) 0,(uchar
*) 0,(my_off_t
) 0,(my_bool
) 0);
382 if (ret_value
== 0 && mi_getint(anc_buff
) > keyinfo
->block_length
)
385 ret_value
=_mi_split_page(info
,keyinfo
,key
,anc_buff
,lastkey
,0) | 2;
387 if (save_flag
&& ret_value
!= 1)
388 ret_value
|=_mi_write_keypage(info
,keyinfo
,page
,DFLT_INIT_HITS
,anc_buff
);
391 DBUG_DUMP("page",(uchar
*) anc_buff
,mi_getint(anc_buff
));
393 my_afree((uchar
*) leaf_buff
);
394 DBUG_PRINT("exit",("Return: %d",ret_value
));
395 DBUG_RETURN(ret_value
);
398 my_afree((uchar
*) leaf_buff
);
399 DBUG_PRINT("exit",("Error: %d",my_errno
));
404 /* Remove a key that has a page-reference */
406 static int del(register MI_INFO
*info
, register MI_KEYDEF
*keyinfo
, uchar
*key
,
407 uchar
*anc_buff
, my_off_t leaf_page
, uchar
*leaf_buff
,
408 uchar
*keypos
, /* Pos to where deleted key was */
410 uchar
*ret_key
) /* key before keypos in anc_buff */
412 int ret_value
,length
;
413 uint a_length
,nod_flag
,tmp
;
415 uchar keybuff
[MI_MAX_KEY_BUFF
],*endpos
,*next_buff
,*key_start
, *prev_key
;
416 MYISAM_SHARE
*share
=info
->s
;
419 DBUG_PRINT("enter",("leaf_page: %ld keypos: 0x%lx", (long) leaf_page
,
421 DBUG_DUMP("leaf_buff",(uchar
*) leaf_buff
,mi_getint(leaf_buff
));
423 endpos
=leaf_buff
+mi_getint(leaf_buff
);
424 if (!(key_start
=_mi_get_last_key(info
,keyinfo
,leaf_buff
,keybuff
,endpos
,
428 if ((nod_flag
=mi_test_if_nod(leaf_buff
)))
430 next_page
= _mi_kpos(nod_flag
,endpos
);
431 if (!(next_buff
= (uchar
*) my_alloca((uint
) keyinfo
->block_length
+
434 if (!_mi_fetch_keypage(info
,keyinfo
,next_page
,DFLT_INIT_HITS
,next_buff
,0))
438 DBUG_DUMP("next_page",(uchar
*) next_buff
,mi_getint(next_buff
));
439 if ((ret_value
=del(info
,keyinfo
,key
,anc_buff
,next_page
,next_buff
,
440 keypos
,next_block
,ret_key
)) >0)
442 endpos
=leaf_buff
+mi_getint(leaf_buff
);
445 ret_value
=underflow(info
,keyinfo
,leaf_buff
,next_page
,
447 if (ret_value
== 0 && mi_getint(leaf_buff
) > keyinfo
->block_length
)
449 ret_value
=_mi_split_page(info
,keyinfo
,key
,leaf_buff
,ret_key
,0) | 2;
454 DBUG_PRINT("test",("Inserting of key when deleting"));
455 if (!_mi_get_last_key(info
,keyinfo
,leaf_buff
,keybuff
,endpos
,
458 ret_value
=_mi_insert(info
,keyinfo
,key
,leaf_buff
,endpos
,keybuff
,
459 (uchar
*) 0,(uchar
*) 0,(my_off_t
) 0,0);
462 if (_mi_write_keypage(info
,keyinfo
,leaf_page
,DFLT_INIT_HITS
,leaf_buff
))
465 my_afree((uchar
*) next_buff
);
466 DBUG_RETURN(ret_value
);
469 /* Remove last key from leaf page */
471 mi_putint(leaf_buff
,key_start
-leaf_buff
,nod_flag
);
472 if (_mi_write_keypage(info
,keyinfo
,leaf_page
,DFLT_INIT_HITS
,leaf_buff
))
475 /* Place last key in ancestor page on deleted key position */
477 a_length
=mi_getint(anc_buff
);
478 endpos
=anc_buff
+a_length
;
479 if (keypos
!= anc_buff
+2+share
->base
.key_reflength
&&
480 !_mi_get_last_key(info
,keyinfo
,anc_buff
,ret_key
,keypos
,&tmp
))
482 prev_key
=(keypos
== anc_buff
+2+share
->base
.key_reflength
?
484 length
=(*keyinfo
->pack_key
)(keyinfo
,share
->base
.key_reflength
,
485 keypos
== endpos
? (uchar
*) 0 : keypos
,
489 bmove_upp((uchar
*) endpos
+length
,(uchar
*) endpos
,(uint
) (endpos
-keypos
));
491 bmove(keypos
,keypos
-length
, (int) (endpos
-keypos
)+length
);
492 (*keyinfo
->store_key
)(keyinfo
,keypos
,&s_temp
);
493 /* Save pointer to next leaf */
494 if (!(*keyinfo
->get_key
)(keyinfo
,share
->base
.key_reflength
,&keypos
,ret_key
))
496 _mi_kpointer(info
,keypos
- share
->base
.key_reflength
,next_block
);
497 mi_putint(anc_buff
,a_length
+length
,share
->base
.key_reflength
);
499 DBUG_RETURN( mi_getint(leaf_buff
) <=
500 (info
->quick_mode
? MI_MIN_KEYBLOCK_LENGTH
:
501 (uint
) keyinfo
->underflow_block_length
));
507 /* Balances adjacent pages if underflow occours */
509 static int underflow(register MI_INFO
*info
, register MI_KEYDEF
*keyinfo
,
511 my_off_t leaf_page
,/* Ancestor page and underflow page */
513 uchar
*keypos
) /* Position to pos after key */
516 uint length
,anc_length
,buff_length
,leaf_length
,p_length
,s_length
,nod_flag
,
517 key_reflength
,key_length
;
519 uchar anc_key
[MI_MAX_KEY_BUFF
],leaf_key
[MI_MAX_KEY_BUFF
],
520 *buff
,*endpos
,*next_keypos
,*anc_pos
,*half_pos
,*temp_pos
,*prev_key
,
523 MYISAM_SHARE
*share
=info
->s
;
524 DBUG_ENTER("underflow");
525 DBUG_PRINT("enter",("leaf_page: %ld keypos: 0x%lx",(long) leaf_page
,
527 DBUG_DUMP("anc_buff",(uchar
*) anc_buff
,mi_getint(anc_buff
));
528 DBUG_DUMP("leaf_buff",(uchar
*) leaf_buff
,mi_getint(leaf_buff
));
533 nod_flag
=mi_test_if_nod(leaf_buff
);
535 anc_length
=mi_getint(anc_buff
);
536 leaf_length
=mi_getint(leaf_buff
);
537 key_reflength
=share
->base
.key_reflength
;
538 if (info
->s
->keyinfo
+info
->lastinx
== keyinfo
)
539 info
->page_changed
=1;
541 if ((keypos
< anc_buff
+anc_length
&& (info
->state
->records
& 1)) ||
542 keypos
== anc_buff
+2+key_reflength
)
543 { /* Use page right of anc-page */
544 DBUG_PRINT("test",("use right page"));
546 if (keyinfo
->flag
& HA_BINARY_PACK_KEY
)
548 if (!(next_keypos
=_mi_get_key(info
, keyinfo
,
549 anc_buff
, buff
, keypos
, &length
)))
554 /* Got to end of found key */
555 buff
[0]=buff
[1]=0; /* Avoid length error check if packed key */
556 if (!(*keyinfo
->get_key
)(keyinfo
,key_reflength
,&next_keypos
,
560 next_page
= _mi_kpos(key_reflength
,next_keypos
);
561 if (!_mi_fetch_keypage(info
,keyinfo
,next_page
,DFLT_INIT_HITS
,buff
,0))
563 buff_length
=mi_getint(buff
);
564 DBUG_DUMP("next",(uchar
*) buff
,buff_length
);
566 /* find keys to make a big key-page */
567 bmove((uchar
*) next_keypos
-key_reflength
,(uchar
*) buff
+2,
569 if (!_mi_get_last_key(info
,keyinfo
,anc_buff
,anc_key
,next_keypos
,&length
)
570 || !_mi_get_last_key(info
,keyinfo
,leaf_buff
,leaf_key
,
571 leaf_buff
+leaf_length
,&length
))
574 /* merge pages and put parting key from anc_buff between */
575 prev_key
=(leaf_length
== p_length
? (uchar
*) 0 : leaf_key
);
576 t_length
=(*keyinfo
->pack_key
)(keyinfo
,nod_flag
,buff
+p_length
,
579 length
=buff_length
-p_length
;
580 endpos
=buff
+length
+leaf_length
+t_length
;
581 /* buff will always be larger than before !*/
582 bmove_upp((uchar
*) endpos
, (uchar
*) buff
+buff_length
,length
);
583 memcpy((uchar
*) buff
, (uchar
*) leaf_buff
,(size_t) leaf_length
);
584 (*keyinfo
->store_key
)(keyinfo
,buff
+leaf_length
,&s_temp
);
585 buff_length
=(uint
) (endpos
-buff
);
586 mi_putint(buff
,buff_length
,nod_flag
);
588 /* remove key from anc_buff */
590 if (!(s_length
=remove_key(keyinfo
,key_reflength
,keypos
,anc_key
,
591 anc_buff
+anc_length
,(my_off_t
*) 0)))
594 anc_length
-=s_length
;
595 mi_putint(anc_buff
,anc_length
,key_reflength
);
597 if (buff_length
<= keyinfo
->block_length
)
598 { /* Keys in one page */
599 memcpy((uchar
*) leaf_buff
,(uchar
*) buff
,(size_t) buff_length
);
600 if (_mi_dispose(info
,keyinfo
,next_page
,DFLT_INIT_HITS
))
605 endpos
=anc_buff
+anc_length
;
606 DBUG_PRINT("test",("anc_buff: 0x%lx endpos: 0x%lx",
607 (long) anc_buff
, (long) endpos
));
608 if (keypos
!= anc_buff
+2+key_reflength
&&
609 !_mi_get_last_key(info
,keyinfo
,anc_buff
,anc_key
,keypos
,&length
))
611 if (!(half_pos
=_mi_find_half_pos(nod_flag
, keyinfo
, buff
, leaf_key
,
612 &key_length
, &after_key
)))
614 length
=(uint
) (half_pos
-buff
);
615 memcpy((uchar
*) leaf_buff
,(uchar
*) buff
,(size_t) length
);
616 mi_putint(leaf_buff
,length
,nod_flag
);
618 /* Correct new keypointer to leaf_page */
620 _mi_kpointer(info
,leaf_key
+key_length
,next_page
);
621 /* Save key in anc_buff */
622 prev_key
=(keypos
== anc_buff
+2+key_reflength
? (uchar
*) 0 : anc_key
),
623 t_length
=(*keyinfo
->pack_key
)(keyinfo
,key_reflength
,
624 (keypos
== endpos
? (uchar
*) 0 :
629 bmove_upp((uchar
*) endpos
+t_length
,(uchar
*) endpos
,
630 (uint
) (endpos
-keypos
));
632 bmove(keypos
,keypos
-t_length
,(uint
) (endpos
-keypos
)+t_length
);
633 (*keyinfo
->store_key
)(keyinfo
,keypos
,&s_temp
);
634 mi_putint(anc_buff
,(anc_length
+=t_length
),key_reflength
);
636 /* Store key first in new page */
638 bmove((uchar
*) buff
+2,(uchar
*) half_pos
-nod_flag
,(size_t) nod_flag
);
639 if (!(*keyinfo
->get_key
)(keyinfo
,nod_flag
,&half_pos
,leaf_key
))
641 t_length
=(int) (*keyinfo
->pack_key
)(keyinfo
, nod_flag
, (uchar
*) 0,
642 (uchar
*) 0, (uchar
*) 0,
644 /* t_length will always be > 0 for a new page !*/
645 length
=(uint
) ((buff
+mi_getint(buff
))-half_pos
);
646 bmove((uchar
*) buff
+p_length
+t_length
,(uchar
*) half_pos
,(size_t) length
);
647 (*keyinfo
->store_key
)(keyinfo
,buff
+p_length
,&s_temp
);
648 mi_putint(buff
,length
+t_length
+p_length
,nod_flag
);
650 if (_mi_write_keypage(info
,keyinfo
,next_page
,DFLT_INIT_HITS
,buff
))
653 if (_mi_write_keypage(info
,keyinfo
,leaf_page
,DFLT_INIT_HITS
,leaf_buff
))
655 DBUG_RETURN(anc_length
<= ((info
->quick_mode
? MI_MIN_BLOCK_LENGTH
:
656 (uint
) keyinfo
->underflow_block_length
)));
659 DBUG_PRINT("test",("use left page"));
661 keypos
=_mi_get_last_key(info
,keyinfo
,anc_buff
,anc_key
,keypos
,&length
);
664 next_page
= _mi_kpos(key_reflength
,keypos
);
665 if (!_mi_fetch_keypage(info
,keyinfo
,next_page
,DFLT_INIT_HITS
,buff
,0))
667 buff_length
=mi_getint(buff
);
668 endpos
=buff
+buff_length
;
669 DBUG_DUMP("prev",(uchar
*) buff
,buff_length
);
671 /* find keys to make a big key-page */
672 bmove((uchar
*) next_keypos
- key_reflength
,(uchar
*) leaf_buff
+2,
675 if (!(*keyinfo
->get_key
)(keyinfo
,key_reflength
,&next_keypos
,
678 if (!_mi_get_last_key(info
,keyinfo
,buff
,leaf_key
,endpos
,&length
))
681 /* merge pages and put parting key from anc_buff between */
682 prev_key
=(leaf_length
== p_length
? (uchar
*) 0 : leaf_key
);
683 t_length
=(*keyinfo
->pack_key
)(keyinfo
,nod_flag
,
684 (leaf_length
== p_length
?
685 (uchar
*) 0 : leaf_buff
+p_length
),
689 bmove((uchar
*) endpos
+t_length
,(uchar
*) leaf_buff
+p_length
,
690 (size_t) (leaf_length
-p_length
));
691 else /* We gained space */
692 bmove((uchar
*) endpos
,(uchar
*) leaf_buff
+((int) p_length
-t_length
),
693 (size_t) (leaf_length
-p_length
+t_length
));
695 (*keyinfo
->store_key
)(keyinfo
,endpos
,&s_temp
);
696 buff_length
=buff_length
+leaf_length
-p_length
+t_length
;
697 mi_putint(buff
,buff_length
,nod_flag
);
699 /* remove key from anc_buff */
700 if (!(s_length
= remove_key(keyinfo
,key_reflength
,keypos
,anc_key
,
701 anc_buff
+anc_length
,(my_off_t
*) 0)))
704 anc_length
-=s_length
;
705 mi_putint(anc_buff
,anc_length
,key_reflength
);
707 if (buff_length
<= keyinfo
->block_length
)
708 { /* Keys in one page */
709 if (_mi_dispose(info
,keyinfo
,leaf_page
,DFLT_INIT_HITS
))
714 if (keypos
== anc_buff
+2+key_reflength
)
715 anc_pos
=0; /* First key */
716 else if (!_mi_get_last_key(info
,keyinfo
,anc_buff
,anc_pos
=anc_key
,keypos
,
719 endpos
=_mi_find_half_pos(nod_flag
,keyinfo
,buff
,leaf_key
,
720 &key_length
, &half_pos
);
723 _mi_kpointer(info
,leaf_key
+key_length
,leaf_page
);
724 /* Save key in anc_buff */
725 DBUG_DUMP("anc_buff",(uchar
*) anc_buff
,anc_length
);
726 DBUG_DUMP("key_to_anc",(uchar
*) leaf_key
,key_length
);
728 temp_pos
=anc_buff
+anc_length
;
729 t_length
=(*keyinfo
->pack_key
)(keyinfo
,key_reflength
,
730 keypos
== temp_pos
? (uchar
*) 0
735 bmove_upp((uchar
*) temp_pos
+t_length
,(uchar
*) temp_pos
,
736 (uint
) (temp_pos
-keypos
));
738 bmove(keypos
,keypos
-t_length
,(uint
) (temp_pos
-keypos
)+t_length
);
739 (*keyinfo
->store_key
)(keyinfo
,keypos
,&s_temp
);
740 mi_putint(anc_buff
,(anc_length
+=t_length
),key_reflength
);
742 /* Store first key on new page */
744 bmove((uchar
*) leaf_buff
+2,(uchar
*) half_pos
-nod_flag
,(size_t) nod_flag
);
745 if (!(length
=(*keyinfo
->get_key
)(keyinfo
,nod_flag
,&half_pos
,leaf_key
)))
747 DBUG_DUMP("key_to_leaf",(uchar
*) leaf_key
,length
);
748 t_length
=(*keyinfo
->pack_key
)(keyinfo
,nod_flag
, (uchar
*) 0,
749 (uchar
*) 0, (uchar
*) 0, leaf_key
, &s_temp
);
750 length
=(uint
) ((buff
+buff_length
)-half_pos
);
751 DBUG_PRINT("info",("t_length: %d length: %d",t_length
,(int) length
));
752 bmove((uchar
*) leaf_buff
+p_length
+t_length
,(uchar
*) half_pos
,
754 (*keyinfo
->store_key
)(keyinfo
,leaf_buff
+p_length
,&s_temp
);
755 mi_putint(leaf_buff
,length
+t_length
+p_length
,nod_flag
);
756 if (_mi_write_keypage(info
,keyinfo
,leaf_page
,DFLT_INIT_HITS
,leaf_buff
))
758 mi_putint(buff
,endpos
-buff
,nod_flag
);
760 if (_mi_write_keypage(info
,keyinfo
,next_page
,DFLT_INIT_HITS
,buff
))
762 DBUG_RETURN(anc_length
<= (uint
) keyinfo
->block_length
/2);
770 remove a key from packed buffert
771 The current code doesn't handle the case that the next key may be
772 packed better against the previous key if there is a case difference
773 returns how many chars was removed or 0 on error
776 static uint
remove_key(MI_KEYDEF
*keyinfo
, uint nod_flag
,
777 uchar
*keypos
, /* Where key starts */
778 uchar
*lastkey
, /* key to be removed */
779 uchar
*page_end
, /* End of page */
780 my_off_t
*next_block
) /* ptr to next block */
784 DBUG_ENTER("remove_key");
785 DBUG_PRINT("enter",("keypos: 0x%lx page_end: 0x%lx",(long) keypos
, (long) page_end
));
788 if (!(keyinfo
->flag
&
789 (HA_PACK_KEY
| HA_SPACE_PACK_USED
| HA_VAR_LENGTH_KEY
|
790 HA_BINARY_PACK_KEY
)))
792 s_length
=(int) (keyinfo
->keylength
+nod_flag
);
793 if (next_block
&& nod_flag
)
794 *next_block
= _mi_kpos(nod_flag
,keypos
+s_length
);
797 { /* Let keypos point at next key */
798 /* Calculate length of key */
799 if (!(*keyinfo
->get_key
)(keyinfo
,nod_flag
,&keypos
,lastkey
))
800 DBUG_RETURN(0); /* Error */
802 if (next_block
&& nod_flag
)
803 *next_block
= _mi_kpos(nod_flag
,keypos
);
804 s_length
=(int) (keypos
-start
);
805 if (keypos
!= page_end
)
807 if (keyinfo
->flag
& HA_BINARY_PACK_KEY
)
809 uchar
*old_key
=start
;
810 uint next_length
,prev_length
,prev_pack_length
;
811 get_key_length(next_length
,keypos
);
812 get_key_pack_length(prev_length
,prev_pack_length
,old_key
);
813 if (next_length
> prev_length
)
815 /* We have to copy data from the current key to the next key */
816 bmove_upp(keypos
, (lastkey
+next_length
),
817 (next_length
-prev_length
));
818 keypos
-=(next_length
-prev_length
)+prev_pack_length
;
819 store_key_length(keypos
,prev_length
);
820 s_length
=(int) (keypos
-start
);
825 /* Check if a variable length first key part */
826 if ((keyinfo
->seg
->flag
& HA_PACK_KEY
) && *keypos
& 128)
828 /* Next key is packed against the current one */
829 uint next_length
,prev_length
,prev_pack_length
,lastkey_length
,
831 if (keyinfo
->seg
[0].length
>= 127)
833 if (!(prev_length
=mi_uint2korr(start
) & 32767))
835 next_length
=mi_uint2korr(keypos
) & 32767;
841 if (!(prev_length
= *start
& 127))
842 goto end
; /* Same key as previous*/
843 next_length
= *keypos
& 127;
848 prev_length
=0; /* prev key not packed */
849 if (keyinfo
->seg
[0].flag
& HA_NULL_PART
)
850 lastkey
++; /* Skip null marker */
851 get_key_length(lastkey_length
,lastkey
);
852 if (!next_length
) /* Same key after */
854 next_length
=lastkey_length
;
858 get_key_length(rest_length
,keypos
);
860 if (next_length
>= prev_length
)
861 { /* Key after is based on deleted key */
862 uint pack_length
,tmp
;
863 bmove_upp(keypos
, (lastkey
+next_length
),
864 tmp
=(next_length
-prev_length
));
866 pack_length
= prev_length
? get_pack_length(rest_length
): 0;
867 keypos
-=tmp
+pack_length
+prev_pack_length
;
868 s_length
=(int) (keypos
-start
);
869 if (prev_length
) /* Pack against prev key */
872 if (prev_pack_length
== 2)
874 store_key_length(keypos
,rest_length
);
878 /* Next key is not packed anymore */
879 if (keyinfo
->seg
[0].flag
& HA_NULL_PART
)
881 rest_length
++; /* Mark not null */
883 if (prev_pack_length
== 2)
885 mi_int2store(keypos
,rest_length
);
888 *keypos
= rest_length
;
896 bmove((uchar
*) start
,(uchar
*) start
+s_length
,
897 (uint
) (page_end
-start
-s_length
));
898 DBUG_RETURN((uint
) s_length
);