1 | /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. |
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; version 2 of the License. |
6 | |
7 | This program is distributed in the hope that it will be useful, |
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | GNU General Public License for more details. |
11 | |
12 | You should have received a copy of the GNU General Public License |
13 | along with this program; if not, write to the Free Software |
14 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
15 | |
16 | /* Remove a row from a MyISAM table */ |
17 | |
18 | #include "fulltext.h" |
19 | #include "rt_index.h" |
20 | |
21 | static int d_search(MI_INFO *info,MI_KEYDEF *keyinfo,uint comp_flag, |
22 | uchar *key,uint key_length,my_off_t page,uchar *anc_buff); |
23 | static int del(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,uchar *anc_buff, |
24 | my_off_t leaf_page,uchar *leaf_buff,uchar *keypos, |
25 | my_off_t next_block,uchar *ret_key); |
26 | static int underflow(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *anc_buff, |
27 | my_off_t leaf_page,uchar *leaf_buff,uchar *keypos); |
28 | static uint remove_key(MI_KEYDEF *keyinfo,uint nod_flag,uchar *keypos, |
29 | uchar *lastkey,uchar *page_end, |
30 | my_off_t *next_block); |
31 | static int _mi_ck_real_delete(register MI_INFO *info,MI_KEYDEF *keyinfo, |
32 | uchar *key, uint key_length, my_off_t *root); |
33 | |
34 | |
35 | int mi_delete(MI_INFO *info,const uchar *record) |
36 | { |
37 | uint i; |
38 | uchar *old_key; |
39 | int save_errno; |
40 | char lastpos[8]; |
41 | |
42 | MYISAM_SHARE *share=info->s; |
43 | DBUG_ENTER("mi_delete" ); |
44 | |
45 | /* Test if record is in datafile */ |
46 | |
47 | DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage" , |
48 | mi_print_error(info->s, HA_ERR_CRASHED); |
49 | DBUG_RETURN(my_errno= HA_ERR_CRASHED);); |
50 | DBUG_EXECUTE_IF("my_error_test_undefined_error" , |
51 | mi_print_error(info->s, INT_MAX); |
52 | DBUG_RETURN(my_errno= INT_MAX);); |
53 | if (!(info->update & HA_STATE_AKTIV)) |
54 | { |
55 | DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND); /* No database read */ |
56 | } |
57 | if (share->options & HA_OPTION_READ_ONLY_DATA) |
58 | { |
59 | DBUG_RETURN(my_errno=EACCES); |
60 | } |
61 | if (_mi_readinfo(info,F_WRLCK,1)) |
62 | DBUG_RETURN(my_errno); |
63 | if (info->s->calc_checksum) |
64 | info->checksum=(*info->s->calc_checksum)(info,record); |
65 | if ((*share->compare_record)(info,record)) |
66 | goto err; /* Error on read-check */ |
67 | |
68 | if (_mi_mark_file_changed(info)) |
69 | goto err; |
70 | |
71 | /* Remove all keys from the .ISAM file */ |
72 | |
73 | old_key=info->lastkey2; |
74 | for (i=0 ; i < share->base.keys ; i++ ) |
75 | { |
76 | if (mi_is_key_active(info->s->state.key_map, i)) |
77 | { |
78 | info->s->keyinfo[i].version++; |
79 | if (info->s->keyinfo[i].flag & HA_FULLTEXT ) |
80 | { |
81 | if (_mi_ft_del(info,i, old_key,record,info->lastpos)) |
82 | goto err; |
83 | } |
84 | else |
85 | { |
86 | if (info->s->keyinfo[i].ck_delete(info,i,old_key, |
87 | _mi_make_key(info,i,old_key,record,info->lastpos))) |
88 | goto err; |
89 | } |
90 | /* The above changed info->lastkey2. Inform mi_rnext_same(). */ |
91 | info->update&= ~HA_STATE_RNEXT_SAME; |
92 | } |
93 | } |
94 | |
95 | if ((*share->delete_record)(info)) |
96 | goto err; /* Remove record from database */ |
97 | info->state->checksum-=info->checksum; |
98 | |
99 | info->update= HA_STATE_CHANGED+HA_STATE_DELETED+HA_STATE_ROW_CHANGED; |
100 | info->state->records--; |
101 | |
102 | mi_sizestore(lastpos,info->lastpos); |
103 | myisam_log_command(MI_LOG_DELETE,info,(uchar*) lastpos,sizeof(lastpos),0); |
104 | (void) _mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE); |
105 | |
106 | if (info->invalidator != 0) |
107 | { |
108 | DBUG_PRINT("info" , ("invalidator... '%s' (delete)" , info->filename)); |
109 | (*info->invalidator)(info->filename); |
110 | info->invalidator=0; |
111 | } |
112 | DBUG_RETURN(0); |
113 | |
114 | err: |
115 | save_errno=my_errno; |
116 | mi_sizestore(lastpos,info->lastpos); |
117 | myisam_log_command(MI_LOG_DELETE,info,(uchar*) lastpos, sizeof(lastpos),0); |
118 | if (save_errno != HA_ERR_RECORD_CHANGED) |
119 | { |
120 | mi_print_error(info->s, HA_ERR_CRASHED); |
121 | mi_mark_crashed(info); /* mark table crashed */ |
122 | } |
123 | (void) _mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE); |
124 | info->update|=HA_STATE_WRITTEN; /* Buffer changed */ |
125 | my_errno=save_errno; |
126 | if (save_errno == HA_ERR_KEY_NOT_FOUND) |
127 | { |
128 | mi_print_error(info->s, HA_ERR_CRASHED); |
129 | my_errno=HA_ERR_CRASHED; |
130 | } |
131 | |
132 | DBUG_RETURN(my_errno); |
133 | } /* mi_delete */ |
134 | |
135 | |
136 | /* Remove a key from the btree index */ |
137 | |
138 | int _mi_ck_delete(register MI_INFO *info, uint keynr, uchar *key, |
139 | uint key_length) |
140 | { |
141 | return _mi_ck_real_delete(info, info->s->keyinfo+keynr, key, key_length, |
142 | &info->s->state.key_root[keynr]); |
143 | } /* _mi_ck_delete */ |
144 | |
145 | |
146 | static int _mi_ck_real_delete(register MI_INFO *info, MI_KEYDEF *keyinfo, |
147 | uchar *key, uint key_length, my_off_t *root) |
148 | { |
149 | int error; |
150 | uint nod_flag; |
151 | my_off_t old_root; |
152 | uchar *root_buff; |
153 | DBUG_ENTER("_mi_ck_real_delete" ); |
154 | |
155 | if ((old_root=*root) == HA_OFFSET_ERROR) |
156 | { |
157 | mi_print_error(info->s, HA_ERR_CRASHED); |
158 | DBUG_RETURN(my_errno=HA_ERR_CRASHED); |
159 | } |
160 | if (!(root_buff= (uchar*) my_alloca((uint) keyinfo->block_length+ |
161 | HA_MAX_KEY_BUFF*2))) |
162 | { |
163 | DBUG_PRINT("error" ,("Couldn't allocate memory" )); |
164 | DBUG_RETURN(my_errno=ENOMEM); |
165 | } |
166 | DBUG_PRINT("info" ,("root_page: %ld" , (long) old_root)); |
167 | if (!_mi_fetch_keypage(info,keyinfo,old_root,DFLT_INIT_HITS,root_buff,0)) |
168 | { |
169 | error= -1; |
170 | goto err; |
171 | } |
172 | if ((error=d_search(info,keyinfo, |
173 | (keyinfo->flag & HA_FULLTEXT ? |
174 | SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT : |
175 | SEARCH_SAME), |
176 | key,key_length,old_root,root_buff)) >0) |
177 | { |
178 | if (error == 2) |
179 | { |
180 | DBUG_PRINT("test" ,("Enlarging of root when deleting" )); |
181 | error=_mi_enlarge_root(info,keyinfo,key,root); |
182 | } |
183 | else /* error == 1 */ |
184 | { |
185 | if (mi_getint(root_buff) <= (nod_flag=mi_test_if_nod(root_buff))+3) |
186 | { |
187 | error=0; |
188 | if (nod_flag) |
189 | *root=_mi_kpos(nod_flag,root_buff+2+nod_flag); |
190 | else |
191 | *root=HA_OFFSET_ERROR; |
192 | if (_mi_dispose(info,keyinfo,old_root,DFLT_INIT_HITS)) |
193 | error= -1; |
194 | } |
195 | else |
196 | error=_mi_write_keypage(info,keyinfo,old_root, |
197 | DFLT_INIT_HITS,root_buff); |
198 | } |
199 | } |
200 | err: |
201 | my_afree((uchar*) root_buff); |
202 | DBUG_PRINT("exit" ,("Return: %d" ,error)); |
203 | DBUG_RETURN(error); |
204 | } /* _mi_ck_real_delete */ |
205 | |
206 | |
207 | /* |
208 | ** Remove key below key root |
209 | ** Return values: |
210 | ** 1 if there are less buffers; In this case anc_buff is not saved |
211 | ** 2 if there are more buffers |
212 | ** -1 on errors |
213 | */ |
214 | |
215 | static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, |
216 | uint comp_flag, uchar *key, uint key_length, |
217 | my_off_t page, uchar *anc_buff) |
218 | { |
219 | int flag,ret_value,save_flag; |
220 | uint length,nod_flag,search_key_length; |
221 | my_bool last_key; |
222 | uchar *leaf_buff,*keypos; |
223 | my_off_t UNINIT_VAR(leaf_page),next_block; |
224 | uchar lastkey[HA_MAX_KEY_BUFF]; |
225 | DBUG_ENTER("d_search" ); |
226 | DBUG_DUMP("page" ,(uchar*) anc_buff,mi_getint(anc_buff)); |
227 | |
228 | search_key_length= (comp_flag & SEARCH_FIND) ? key_length : USE_WHOLE_KEY; |
229 | flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key, search_key_length, |
230 | comp_flag, &keypos, lastkey, &last_key); |
231 | if (flag == MI_FOUND_WRONG_KEY) |
232 | { |
233 | DBUG_PRINT("error" ,("Found wrong key" )); |
234 | DBUG_RETURN(-1); |
235 | } |
236 | nod_flag=mi_test_if_nod(anc_buff); |
237 | |
238 | if (!flag && keyinfo->flag & HA_FULLTEXT) |
239 | { |
240 | uint off; |
241 | int subkeys; |
242 | |
243 | get_key_full_length_rdonly(off, lastkey); |
244 | subkeys=ft_sintXkorr(lastkey+off); |
245 | DBUG_ASSERT(info->ft1_to_ft2==0 || subkeys >=0); |
246 | comp_flag=SEARCH_SAME; |
247 | if (subkeys >= 0) |
248 | { |
249 | /* normal word, one-level tree structure */ |
250 | if (info->ft1_to_ft2) |
251 | { |
252 | /* we're in ft1->ft2 conversion mode. Saving key data */ |
253 | if (insert_dynamic(info->ft1_to_ft2, (lastkey+off))) |
254 | { |
255 | DBUG_PRINT("error" ,("Out of memory" )); |
256 | DBUG_RETURN(-1); |
257 | } |
258 | } |
259 | else |
260 | { |
261 | /* we need exact match only if not in ft1->ft2 conversion mode */ |
262 | flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key,USE_WHOLE_KEY, |
263 | comp_flag, &keypos, lastkey, &last_key); |
264 | } |
265 | /* fall through to normal delete */ |
266 | } |
267 | else |
268 | { |
269 | /* popular word. two-level tree. going down */ |
270 | uint tmp_key_length; |
271 | my_off_t root; |
272 | uchar *kpos=keypos; |
273 | |
274 | if (!(tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&kpos,lastkey))) |
275 | { |
276 | mi_print_error(info->s, HA_ERR_CRASHED); |
277 | my_errno= HA_ERR_CRASHED; |
278 | DBUG_RETURN(-1); |
279 | } |
280 | root=_mi_dpos(info,nod_flag,kpos); |
281 | if (subkeys == -1) |
282 | { |
283 | /* the last entry in sub-tree */ |
284 | if (_mi_dispose(info, keyinfo, root,DFLT_INIT_HITS)) |
285 | DBUG_RETURN(-1); |
286 | /* fall through to normal delete */ |
287 | } |
288 | else |
289 | { |
290 | keyinfo=&info->s->ft2_keyinfo; |
291 | kpos-=keyinfo->keylength+nod_flag; /* we'll modify key entry 'in vivo' */ |
292 | get_key_full_length_rdonly(off, key); |
293 | key+=off; |
294 | ret_value=_mi_ck_real_delete(info, &info->s->ft2_keyinfo, |
295 | key, HA_FT_WLEN, &root); |
296 | _mi_dpointer(info, kpos+HA_FT_WLEN, root); |
297 | subkeys++; |
298 | ft_intXstore(kpos, subkeys); |
299 | if (!ret_value) |
300 | ret_value=_mi_write_keypage(info,keyinfo,page, |
301 | DFLT_INIT_HITS,anc_buff); |
302 | DBUG_PRINT("exit" ,("Return: %d" ,ret_value)); |
303 | DBUG_RETURN(ret_value); |
304 | } |
305 | } |
306 | } |
307 | leaf_buff=0; |
308 | if (nod_flag) |
309 | { |
310 | leaf_page=_mi_kpos(nod_flag,keypos); |
311 | if (!(leaf_buff= (uchar*) my_alloca((uint) keyinfo->block_length+ |
312 | HA_MAX_KEY_BUFF*2))) |
313 | { |
314 | DBUG_PRINT("error" ,("Couldn't allocate memory" )); |
315 | my_errno=ENOMEM; |
316 | DBUG_PRINT("exit" ,("Return: %d" ,-1)); |
317 | DBUG_RETURN(-1); |
318 | } |
319 | if (!_mi_fetch_keypage(info,keyinfo,leaf_page,DFLT_INIT_HITS,leaf_buff,0)) |
320 | goto err; |
321 | } |
322 | |
323 | if (flag != 0) |
324 | { |
325 | if (!nod_flag) |
326 | { |
327 | DBUG_PRINT("error" ,("Didn't find key" )); |
328 | mi_print_error(info->s, HA_ERR_CRASHED); |
329 | my_errno=HA_ERR_CRASHED; /* This should never happend */ |
330 | goto err; |
331 | } |
332 | save_flag=0; |
333 | ret_value=d_search(info,keyinfo,comp_flag,key,key_length, |
334 | leaf_page,leaf_buff); |
335 | } |
336 | else |
337 | { /* Found key */ |
338 | uint tmp; |
339 | length=mi_getint(anc_buff); |
340 | if (!(tmp= remove_key(keyinfo,nod_flag,keypos,lastkey,anc_buff+length, |
341 | &next_block))) |
342 | goto err; |
343 | |
344 | length-= tmp; |
345 | |
346 | mi_putint(anc_buff,length,nod_flag); |
347 | if (!nod_flag) |
348 | { /* On leaf page */ |
349 | if (_mi_write_keypage(info,keyinfo,page,DFLT_INIT_HITS,anc_buff)) |
350 | { |
351 | DBUG_PRINT("exit" ,("Return: %d" ,-1)); |
352 | DBUG_RETURN(-1); |
353 | } |
354 | /* Page will be update later if we return 1 */ |
355 | DBUG_RETURN(MY_TEST(length <= (info->quick_mode ? MI_MIN_KEYBLOCK_LENGTH : |
356 | (uint) keyinfo->underflow_block_length))); |
357 | } |
358 | save_flag=1; |
359 | ret_value=del(info,keyinfo,key,anc_buff,leaf_page,leaf_buff,keypos, |
360 | next_block,lastkey); |
361 | } |
362 | if (ret_value >0) |
363 | { |
364 | save_flag=1; |
365 | if (ret_value == 1) |
366 | ret_value= underflow(info,keyinfo,anc_buff,leaf_page,leaf_buff,keypos); |
367 | else |
368 | { /* This happens only with packed keys */ |
369 | DBUG_PRINT("test" ,("Enlarging of key when deleting" )); |
370 | if (!_mi_get_last_key(info,keyinfo,anc_buff,lastkey,keypos,&length)) |
371 | goto err; |
372 | ret_value=_mi_insert(info,keyinfo,key,anc_buff,keypos,lastkey, |
373 | (uchar*) 0,(uchar*) 0,(my_off_t) 0,(my_bool) 0); |
374 | } |
375 | } |
376 | if (ret_value == 0 && mi_getint(anc_buff) > keyinfo->block_length) |
377 | { |
378 | save_flag=1; |
379 | ret_value=_mi_split_page(info,keyinfo,key,anc_buff,lastkey,0) | 2; |
380 | } |
381 | if (save_flag && ret_value != 1) |
382 | ret_value|=_mi_write_keypage(info,keyinfo,page,DFLT_INIT_HITS,anc_buff); |
383 | else |
384 | { |
385 | DBUG_DUMP("page" ,(uchar*) anc_buff,mi_getint(anc_buff)); |
386 | } |
387 | my_afree((uchar*) leaf_buff); |
388 | DBUG_PRINT("exit" ,("Return: %d" ,ret_value)); |
389 | DBUG_RETURN(ret_value); |
390 | |
391 | err: |
392 | my_afree((uchar*) leaf_buff); |
393 | DBUG_PRINT("exit" ,("Error: %d" ,my_errno)); |
394 | DBUG_RETURN (-1); |
395 | } /* d_search */ |
396 | |
397 | |
398 | /* Remove a key that has a page-reference */ |
399 | |
400 | static int del(register MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *key, |
401 | uchar *anc_buff, my_off_t leaf_page, uchar *leaf_buff, |
402 | uchar *keypos, /* Pos to where deleted key was */ |
403 | my_off_t next_block, |
404 | uchar *ret_key) /* key before keypos in anc_buff */ |
405 | { |
406 | int ret_value,length; |
407 | uint a_length,nod_flag,tmp; |
408 | my_off_t next_page; |
409 | uchar keybuff[HA_MAX_KEY_BUFF],*endpos,*next_buff,*key_start, *prev_key; |
410 | MYISAM_SHARE *share=info->s; |
411 | MI_KEY_PARAM s_temp; |
412 | DBUG_ENTER("del" ); |
413 | DBUG_PRINT("enter" ,("leaf_page: %lld keypos: %p" , leaf_page, |
414 | keypos)); |
415 | DBUG_DUMP("leaf_buff" ,(uchar*) leaf_buff,mi_getint(leaf_buff)); |
416 | |
417 | endpos=leaf_buff+mi_getint(leaf_buff); |
418 | if (!(key_start=_mi_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos, |
419 | &tmp))) |
420 | DBUG_RETURN(-1); |
421 | |
422 | if ((nod_flag=mi_test_if_nod(leaf_buff))) |
423 | { |
424 | next_page= _mi_kpos(nod_flag,endpos); |
425 | if (!(next_buff= (uchar*) my_alloca((uint) keyinfo->block_length+ |
426 | HA_MAX_KEY_BUFF*2))) |
427 | DBUG_RETURN(-1); |
428 | if (!_mi_fetch_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,next_buff,0)) |
429 | ret_value= -1; |
430 | else |
431 | { |
432 | DBUG_DUMP("next_page" ,(uchar*) next_buff,mi_getint(next_buff)); |
433 | if ((ret_value=del(info,keyinfo,key,anc_buff,next_page,next_buff, |
434 | keypos,next_block,ret_key)) >0) |
435 | { |
436 | endpos=leaf_buff+mi_getint(leaf_buff); |
437 | if (ret_value == 1) |
438 | { |
439 | ret_value=underflow(info,keyinfo,leaf_buff,next_page, |
440 | next_buff,endpos); |
441 | if (ret_value == 0 && mi_getint(leaf_buff) > keyinfo->block_length) |
442 | { |
443 | ret_value=_mi_split_page(info,keyinfo,key,leaf_buff,ret_key,0) | 2; |
444 | } |
445 | } |
446 | else |
447 | { |
448 | DBUG_PRINT("test" ,("Inserting of key when deleting" )); |
449 | if (!_mi_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos, |
450 | &tmp)) |
451 | goto err; |
452 | ret_value=_mi_insert(info,keyinfo,key,leaf_buff,endpos,keybuff, |
453 | (uchar*) 0,(uchar*) 0,(my_off_t) 0,0); |
454 | } |
455 | } |
456 | if (_mi_write_keypage(info,keyinfo,leaf_page,DFLT_INIT_HITS,leaf_buff)) |
457 | goto err; |
458 | } |
459 | my_afree((uchar*) next_buff); |
460 | DBUG_RETURN(ret_value); |
461 | } |
462 | |
463 | /* Remove last key from leaf page */ |
464 | |
465 | mi_putint(leaf_buff,key_start-leaf_buff,nod_flag); |
466 | if (_mi_write_keypage(info,keyinfo,leaf_page,DFLT_INIT_HITS,leaf_buff)) |
467 | goto err; |
468 | |
469 | /* Place last key in ancestor page on deleted key position */ |
470 | |
471 | a_length=mi_getint(anc_buff); |
472 | endpos=anc_buff+a_length; |
473 | if (keypos != anc_buff+2+share->base.key_reflength && |
474 | !_mi_get_last_key(info,keyinfo,anc_buff,ret_key,keypos,&tmp)) |
475 | goto err; |
476 | prev_key=(keypos == anc_buff+2+share->base.key_reflength ? |
477 | 0 : ret_key); |
478 | length=(*keyinfo->pack_key)(keyinfo,share->base.key_reflength, |
479 | keypos == endpos ? (uchar*) 0 : keypos, |
480 | prev_key, prev_key, |
481 | keybuff,&s_temp); |
482 | if (length > 0) |
483 | bmove_upp((uchar*) endpos+length,(uchar*) endpos,(uint) (endpos-keypos)); |
484 | else |
485 | bmove(keypos,keypos-length, (int) (endpos-keypos)+length); |
486 | (*keyinfo->store_key)(keyinfo,keypos,&s_temp); |
487 | /* Save pointer to next leaf */ |
488 | if (!(*keyinfo->get_key)(keyinfo,share->base.key_reflength,&keypos,ret_key)) |
489 | goto err; |
490 | _mi_kpointer(info,keypos - share->base.key_reflength,next_block); |
491 | mi_putint(anc_buff,a_length+length,share->base.key_reflength); |
492 | |
493 | DBUG_RETURN( mi_getint(leaf_buff) <= |
494 | (info->quick_mode ? MI_MIN_KEYBLOCK_LENGTH : |
495 | (uint) keyinfo->underflow_block_length)); |
496 | err: |
497 | DBUG_RETURN(-1); |
498 | } /* del */ |
499 | |
500 | |
501 | /* Balances adjacent pages if underflow occours */ |
502 | |
503 | static int underflow(register MI_INFO *info, register MI_KEYDEF *keyinfo, |
504 | uchar *anc_buff, |
505 | my_off_t leaf_page,/* Ancestor page and underflow page */ |
506 | uchar *leaf_buff, |
507 | uchar *keypos) /* Position to pos after key */ |
508 | { |
509 | int t_length; |
510 | uint length,anc_length,buff_length,leaf_length,p_length,s_length,nod_flag, |
511 | key_reflength,key_length; |
512 | my_off_t next_page; |
513 | uchar anc_key[HA_MAX_KEY_BUFF],leaf_key[HA_MAX_KEY_BUFF], |
514 | *buff,*endpos,*next_keypos,*anc_pos,*half_pos,*temp_pos,*prev_key, |
515 | *after_key; |
516 | MI_KEY_PARAM s_temp; |
517 | MYISAM_SHARE *share=info->s; |
518 | DBUG_ENTER("underflow" ); |
519 | DBUG_PRINT("enter" ,("leaf_page: %lld keypos: %p" ,leaf_page, |
520 | keypos)); |
521 | DBUG_DUMP("anc_buff" ,(uchar*) anc_buff,mi_getint(anc_buff)); |
522 | DBUG_DUMP("leaf_buff" ,(uchar*) leaf_buff,mi_getint(leaf_buff)); |
523 | |
524 | buff=info->buff; |
525 | info->buff_used=1; |
526 | next_keypos=keypos; |
527 | nod_flag=mi_test_if_nod(leaf_buff); |
528 | p_length=nod_flag+2; |
529 | anc_length=mi_getint(anc_buff); |
530 | leaf_length=mi_getint(leaf_buff); |
531 | key_reflength=share->base.key_reflength; |
532 | if (info->s->keyinfo+info->lastinx == keyinfo) |
533 | info->page_changed=1; |
534 | |
535 | if ((keypos < anc_buff+anc_length && (info->state->records & 1)) || |
536 | keypos == anc_buff+2+key_reflength) |
537 | { /* Use page right of anc-page */ |
538 | DBUG_PRINT("test" ,("use right page" )); |
539 | |
540 | if (keyinfo->flag & HA_BINARY_PACK_KEY) |
541 | { |
542 | if (!(next_keypos=_mi_get_key(info, keyinfo, |
543 | anc_buff, buff, keypos, &length))) |
544 | goto err; |
545 | } |
546 | else |
547 | { |
548 | /* Got to end of found key */ |
549 | buff[0]=buff[1]=0; /* Avoid length error check if packed key */ |
550 | if (!(*keyinfo->get_key)(keyinfo,key_reflength,&next_keypos, |
551 | buff)) |
552 | goto err; |
553 | } |
554 | next_page= _mi_kpos(key_reflength,next_keypos); |
555 | if (!_mi_fetch_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,buff,0)) |
556 | goto err; |
557 | buff_length=mi_getint(buff); |
558 | DBUG_DUMP("next" ,(uchar*) buff,buff_length); |
559 | |
560 | /* find keys to make a big key-page */ |
561 | bmove((uchar*) next_keypos-key_reflength,(uchar*) buff+2, |
562 | key_reflength); |
563 | if (!_mi_get_last_key(info,keyinfo,anc_buff,anc_key,next_keypos,&length) |
564 | || !_mi_get_last_key(info,keyinfo,leaf_buff,leaf_key, |
565 | leaf_buff+leaf_length,&length)) |
566 | goto err; |
567 | |
568 | /* merge pages and put parting key from anc_buff between */ |
569 | prev_key=(leaf_length == p_length ? (uchar*) 0 : leaf_key); |
570 | t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,buff+p_length, |
571 | prev_key, prev_key, |
572 | anc_key, &s_temp); |
573 | length=buff_length-p_length; |
574 | endpos=buff+length+leaf_length+t_length; |
575 | /* buff will always be larger than before !*/ |
576 | bmove_upp((uchar*) endpos, (uchar*) buff+buff_length,length); |
577 | memcpy((uchar*) buff, (uchar*) leaf_buff,(size_t) leaf_length); |
578 | (*keyinfo->store_key)(keyinfo,buff+leaf_length,&s_temp); |
579 | buff_length=(uint) (endpos-buff); |
580 | mi_putint(buff,buff_length,nod_flag); |
581 | |
582 | /* remove key from anc_buff */ |
583 | |
584 | if (!(s_length=remove_key(keyinfo,key_reflength,keypos,anc_key, |
585 | anc_buff+anc_length,(my_off_t *) 0))) |
586 | goto err; |
587 | |
588 | anc_length-=s_length; |
589 | mi_putint(anc_buff,anc_length,key_reflength); |
590 | |
591 | if (buff_length <= keyinfo->block_length) |
592 | { /* Keys in one page */ |
593 | memcpy((uchar*) leaf_buff,(uchar*) buff,(size_t) buff_length); |
594 | if (_mi_dispose(info,keyinfo,next_page,DFLT_INIT_HITS)) |
595 | goto err; |
596 | } |
597 | else |
598 | { /* Page is full */ |
599 | endpos=anc_buff+anc_length; |
600 | DBUG_PRINT("test" ,("anc_buff: %p endpos: %p" , |
601 | anc_buff, endpos)); |
602 | if (keypos != anc_buff+2+key_reflength && |
603 | !_mi_get_last_key(info,keyinfo,anc_buff,anc_key,keypos,&length)) |
604 | goto err; |
605 | if (!(half_pos=_mi_find_half_pos(nod_flag, keyinfo, buff, leaf_key, |
606 | &key_length, &after_key))) |
607 | goto err; |
608 | length=(uint) (half_pos-buff); |
609 | memcpy((uchar*) leaf_buff,(uchar*) buff,(size_t) length); |
610 | mi_putint(leaf_buff,length,nod_flag); |
611 | |
612 | /* Correct new keypointer to leaf_page */ |
613 | half_pos=after_key; |
614 | _mi_kpointer(info,leaf_key+key_length,next_page); |
615 | /* Save key in anc_buff */ |
616 | prev_key=(keypos == anc_buff+2+key_reflength ? (uchar*) 0 : anc_key), |
617 | t_length=(*keyinfo->pack_key)(keyinfo,key_reflength, |
618 | (keypos == endpos ? (uchar*) 0 : |
619 | keypos), |
620 | prev_key, prev_key, |
621 | leaf_key, &s_temp); |
622 | if (t_length >= 0) |
623 | bmove_upp((uchar*) endpos+t_length,(uchar*) endpos, |
624 | (uint) (endpos-keypos)); |
625 | else |
626 | bmove(keypos,keypos-t_length,(uint) (endpos-keypos)+t_length); |
627 | (*keyinfo->store_key)(keyinfo,keypos,&s_temp); |
628 | mi_putint(anc_buff,(anc_length+=t_length),key_reflength); |
629 | |
630 | /* Store key first in new page */ |
631 | if (nod_flag) |
632 | bmove((uchar*) buff+2,(uchar*) half_pos-nod_flag,(size_t) nod_flag); |
633 | if (!(*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key)) |
634 | goto err; |
635 | t_length=(int) (*keyinfo->pack_key)(keyinfo, nod_flag, (uchar*) 0, |
636 | (uchar*) 0, (uchar *) 0, |
637 | leaf_key, &s_temp); |
638 | /* t_length will always be > 0 for a new page !*/ |
639 | length=(uint) ((buff+mi_getint(buff))-half_pos); |
640 | bmove((uchar*) buff+p_length+t_length,(uchar*) half_pos,(size_t) length); |
641 | (*keyinfo->store_key)(keyinfo,buff+p_length,&s_temp); |
642 | mi_putint(buff,length+t_length+p_length,nod_flag); |
643 | |
644 | if (_mi_write_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,buff)) |
645 | goto err; |
646 | } |
647 | if (_mi_write_keypage(info,keyinfo,leaf_page,DFLT_INIT_HITS,leaf_buff)) |
648 | goto err; |
649 | DBUG_RETURN(anc_length <= ((info->quick_mode ? MI_MIN_BLOCK_LENGTH : |
650 | (uint) keyinfo->underflow_block_length))); |
651 | } |
652 | |
653 | DBUG_PRINT("test" ,("use left page" )); |
654 | |
655 | keypos=_mi_get_last_key(info,keyinfo,anc_buff,anc_key,keypos,&length); |
656 | if (!keypos) |
657 | goto err; |
658 | next_page= _mi_kpos(key_reflength,keypos); |
659 | if (!_mi_fetch_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,buff,0)) |
660 | goto err; |
661 | buff_length=mi_getint(buff); |
662 | endpos=buff+buff_length; |
663 | DBUG_DUMP("prev" ,(uchar*) buff,buff_length); |
664 | |
665 | /* find keys to make a big key-page */ |
666 | bmove((uchar*) next_keypos - key_reflength,(uchar*) leaf_buff+2, |
667 | key_reflength); |
668 | next_keypos=keypos; |
669 | if (!(*keyinfo->get_key)(keyinfo,key_reflength,&next_keypos, |
670 | anc_key)) |
671 | goto err; |
672 | if (!_mi_get_last_key(info,keyinfo,buff,leaf_key,endpos,&length)) |
673 | goto err; |
674 | |
675 | /* merge pages and put parting key from anc_buff between */ |
676 | prev_key=(leaf_length == p_length ? (uchar*) 0 : leaf_key); |
677 | t_length=(*keyinfo->pack_key)(keyinfo,nod_flag, |
678 | (leaf_length == p_length ? |
679 | (uchar*) 0 : leaf_buff+p_length), |
680 | prev_key, prev_key, |
681 | anc_key, &s_temp); |
682 | if (t_length >= 0) |
683 | bmove((uchar*) endpos+t_length,(uchar*) leaf_buff+p_length, |
684 | (size_t) (leaf_length-p_length)); |
685 | else /* We gained space */ |
686 | bmove((uchar*) endpos,(uchar*) leaf_buff+((int) p_length-t_length), |
687 | (size_t) (leaf_length-p_length+t_length)); |
688 | |
689 | (*keyinfo->store_key)(keyinfo,endpos,&s_temp); |
690 | buff_length=buff_length+leaf_length-p_length+t_length; |
691 | mi_putint(buff,buff_length,nod_flag); |
692 | |
693 | /* remove key from anc_buff */ |
694 | if (!(s_length= remove_key(keyinfo,key_reflength,keypos,anc_key, |
695 | anc_buff+anc_length,(my_off_t *) 0))) |
696 | goto err; |
697 | |
698 | anc_length-=s_length; |
699 | mi_putint(anc_buff,anc_length,key_reflength); |
700 | |
701 | if (buff_length <= keyinfo->block_length) |
702 | { /* Keys in one page */ |
703 | if (_mi_dispose(info,keyinfo,leaf_page,DFLT_INIT_HITS)) |
704 | goto err; |
705 | } |
706 | else |
707 | { /* Page is full */ |
708 | if (keypos == anc_buff+2+key_reflength) |
709 | anc_pos=0; /* First key */ |
710 | else if (!_mi_get_last_key(info,keyinfo,anc_buff,anc_pos=anc_key,keypos, |
711 | &length)) |
712 | goto err; |
713 | endpos=_mi_find_half_pos(nod_flag,keyinfo,buff,leaf_key, |
714 | &key_length, &half_pos); |
715 | if (!endpos) |
716 | goto err; |
717 | _mi_kpointer(info,leaf_key+key_length,leaf_page); |
718 | /* Save key in anc_buff */ |
719 | DBUG_DUMP("anc_buff" ,(uchar*) anc_buff,anc_length); |
720 | DBUG_DUMP("key_to_anc" ,(uchar*) leaf_key,key_length); |
721 | |
722 | temp_pos=anc_buff+anc_length; |
723 | t_length=(*keyinfo->pack_key)(keyinfo,key_reflength, |
724 | keypos == temp_pos ? (uchar*) 0 |
725 | : keypos, |
726 | anc_pos, anc_pos, |
727 | leaf_key,&s_temp); |
728 | if (t_length > 0) |
729 | bmove_upp((uchar*) temp_pos+t_length,(uchar*) temp_pos, |
730 | (uint) (temp_pos-keypos)); |
731 | else |
732 | bmove(keypos,keypos-t_length,(uint) (temp_pos-keypos)+t_length); |
733 | (*keyinfo->store_key)(keyinfo,keypos,&s_temp); |
734 | mi_putint(anc_buff,(anc_length+=t_length),key_reflength); |
735 | |
736 | /* Store first key on new page */ |
737 | if (nod_flag) |
738 | bmove((uchar*) leaf_buff+2,(uchar*) half_pos-nod_flag,(size_t) nod_flag); |
739 | if (!(length=(*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key))) |
740 | goto err; |
741 | DBUG_DUMP("key_to_leaf" ,(uchar*) leaf_key,length); |
742 | t_length=(*keyinfo->pack_key)(keyinfo,nod_flag, (uchar*) 0, |
743 | (uchar*) 0, (uchar*) 0, leaf_key, &s_temp); |
744 | length=(uint) ((buff+buff_length)-half_pos); |
745 | DBUG_PRINT("info" ,("t_length: %d length: %d" ,t_length,(int) length)); |
746 | bmove((uchar*) leaf_buff+p_length+t_length,(uchar*) half_pos, |
747 | (size_t) length); |
748 | (*keyinfo->store_key)(keyinfo,leaf_buff+p_length,&s_temp); |
749 | mi_putint(leaf_buff,length+t_length+p_length,nod_flag); |
750 | if (_mi_write_keypage(info,keyinfo,leaf_page,DFLT_INIT_HITS,leaf_buff)) |
751 | goto err; |
752 | mi_putint(buff,endpos-buff,nod_flag); |
753 | } |
754 | if (_mi_write_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,buff)) |
755 | goto err; |
756 | DBUG_RETURN(anc_length <= (uint) keyinfo->block_length/2); |
757 | |
758 | err: |
759 | DBUG_RETURN(-1); |
760 | } /* underflow */ |
761 | |
762 | |
763 | /* |
764 | remove a key from packed buffert |
765 | The current code doesn't handle the case that the next key may be |
766 | packed better against the previous key if there is a case difference |
767 | returns how many chars was removed or 0 on error |
768 | */ |
769 | |
770 | static uint remove_key(MI_KEYDEF *keyinfo, uint nod_flag, |
771 | uchar *keypos, /* Where key starts */ |
772 | uchar *lastkey, /* key to be removed */ |
773 | uchar *page_end, /* End of page */ |
774 | my_off_t *next_block) /* ptr to next block */ |
775 | { |
776 | int s_length; |
777 | uchar *start; |
778 | DBUG_ENTER("remove_key" ); |
779 | DBUG_PRINT("enter" ,("keypos: %p page_end: %p" ,keypos, page_end)); |
780 | |
781 | start=keypos; |
782 | if (!(keyinfo->flag & |
783 | (HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY | |
784 | HA_BINARY_PACK_KEY))) |
785 | { |
786 | s_length=(int) (keyinfo->keylength+nod_flag); |
787 | if (next_block && nod_flag) |
788 | *next_block= _mi_kpos(nod_flag,keypos+s_length); |
789 | } |
790 | else |
791 | { /* Let keypos point at next key */ |
792 | /* Calculate length of key */ |
793 | if (!(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey)) |
794 | DBUG_RETURN(0); /* Error */ |
795 | |
796 | if (next_block && nod_flag) |
797 | *next_block= _mi_kpos(nod_flag,keypos); |
798 | s_length=(int) (keypos-start); |
799 | if (keypos != page_end) |
800 | { |
801 | if (keyinfo->flag & HA_BINARY_PACK_KEY) |
802 | { |
803 | uchar *old_key=start; |
804 | uint next_length,prev_length,prev_pack_length; |
805 | get_key_length(next_length,keypos); |
806 | get_key_pack_length(prev_length,prev_pack_length,old_key); |
807 | if (next_length > prev_length) |
808 | { |
809 | /* We have to copy data from the current key to the next key */ |
810 | bmove_upp(keypos, (lastkey+next_length), |
811 | (next_length-prev_length)); |
812 | keypos-=(next_length-prev_length)+prev_pack_length; |
813 | store_key_length(keypos,prev_length); |
814 | s_length=(int) (keypos-start); |
815 | } |
816 | } |
817 | else |
818 | { |
819 | /* Check if a variable length first key part */ |
820 | if ((keyinfo->seg->flag & HA_PACK_KEY) && *keypos & 128) |
821 | { |
822 | /* Next key is packed against the current one */ |
823 | uint next_length,prev_length,prev_pack_length,lastkey_length, |
824 | rest_length; |
825 | if (keyinfo->seg[0].length >= 127) |
826 | { |
827 | if (!(prev_length=mi_uint2korr(start) & 32767)) |
828 | goto end; |
829 | next_length=mi_uint2korr(keypos) & 32767; |
830 | keypos+=2; |
831 | prev_pack_length=2; |
832 | } |
833 | else |
834 | { |
835 | if (!(prev_length= *start & 127)) |
836 | goto end; /* Same key as previous*/ |
837 | next_length= *keypos & 127; |
838 | keypos++; |
839 | prev_pack_length=1; |
840 | } |
841 | if (!(*start & 128)) |
842 | prev_length=0; /* prev key not packed */ |
843 | if (keyinfo->seg[0].flag & HA_NULL_PART) |
844 | lastkey++; /* Skip null marker */ |
845 | get_key_length(lastkey_length,lastkey); |
846 | if (!next_length) /* Same key after */ |
847 | { |
848 | next_length=lastkey_length; |
849 | rest_length=0; |
850 | } |
851 | else |
852 | get_key_length(rest_length,keypos); |
853 | |
854 | if (next_length >= prev_length) |
855 | { /* Key after is based on deleted key */ |
856 | uint pack_length,tmp; |
857 | bmove_upp(keypos, (lastkey+next_length), |
858 | tmp=(next_length-prev_length)); |
859 | rest_length+=tmp; |
860 | pack_length= prev_length ? get_pack_length(rest_length): 0; |
861 | keypos-=tmp+pack_length+prev_pack_length; |
862 | s_length=(int) (keypos-start); |
863 | if (prev_length) /* Pack against prev key */ |
864 | { |
865 | *keypos++= start[0]; |
866 | if (prev_pack_length == 2) |
867 | *keypos++= start[1]; |
868 | store_key_length(keypos,rest_length); |
869 | } |
870 | else |
871 | { |
872 | /* Next key is not packed anymore */ |
873 | if (keyinfo->seg[0].flag & HA_NULL_PART) |
874 | { |
875 | rest_length++; /* Mark not null */ |
876 | } |
877 | if (prev_pack_length == 2) |
878 | { |
879 | mi_int2store(keypos,rest_length); |
880 | } |
881 | else |
882 | *keypos= rest_length; |
883 | } |
884 | } |
885 | } |
886 | } |
887 | } |
888 | } |
889 | end: |
890 | bmove((uchar*) start,(uchar*) start+s_length, |
891 | (uint) (page_end-start-s_length)); |
892 | DBUG_RETURN((uint) s_length); |
893 | } /* remove_key */ |
894 | |