MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
rt_index.c
1 /* Copyright (c) 2002, 2010, 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 Street, Fifth Floor, Boston, MA 02110-1301, USA */
15 
16 #include "myisamdef.h"
17 
18 #ifdef HAVE_RTREE_KEYS
19 
20 #include "rt_index.h"
21 #include "rt_key.h"
22 #include "rt_mbr.h"
23 
24 #define REINSERT_BUFFER_INC 10
25 #define PICK_BY_AREA
26 /*#define PICK_BY_PERIMETER*/
27 
28 typedef struct st_page_level
29 {
30  uint level;
31  my_off_t offs;
32 } stPageLevel;
33 
34 typedef struct st_page_list
35 {
36  ulong n_pages;
37  ulong m_pages;
38  stPageLevel *pages;
39 } stPageList;
40 
41 
42 /*
43  Find next key in r-tree according to search_flag recursively
44 
45  NOTES
46  Used in rtree_find_first() and rtree_find_next()
47 
48  RETURN
49  -1 Error
50  0 Found
51  1 Not found
52 */
53 
54 static int rtree_find_req(MI_INFO *info, MI_KEYDEF *keyinfo, uint search_flag,
55  uint nod_cmp_flag, my_off_t page, int level)
56 {
57  uchar *k;
58  uchar *last;
59  uint nod_flag;
60  int res;
61  uchar *page_buf;
62  int k_len;
63  uint *saved_key = (uint*) (info->rtree_recursion_state) + level;
64 
65  if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
66  {
67  my_errno = HA_ERR_OUT_OF_MEM;
68  return -1;
69  }
70  if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0))
71  goto err1;
72  nod_flag = mi_test_if_nod(page_buf);
73 
74  k_len = keyinfo->keylength - info->s->base.rec_reflength;
75 
76  if(info->rtree_recursion_depth >= level)
77  {
78  k = page_buf + *saved_key;
79  }
80  else
81  {
82  k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
83  }
84  last = rt_PAGE_END(page_buf);
85 
86  for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag))
87  {
88  if (nod_flag)
89  {
90  /* this is an internal node in the tree */
91  if (!(res = rtree_key_cmp(keyinfo->seg, info->first_mbr_key, k,
92  info->last_rkey_length, nod_cmp_flag)))
93  {
94  switch ((res = rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag,
95  _mi_kpos(nod_flag, k), level + 1)))
96  {
97  case 0: /* found - exit from recursion */
98  *saved_key = (uint) (k - page_buf);
99  goto ok;
100  case 1: /* not found - continue searching */
101  info->rtree_recursion_depth = level;
102  break;
103  default: /* error */
104  case -1:
105  goto err1;
106  }
107  }
108  }
109  else
110  {
111  /* this is a leaf */
112  if (!rtree_key_cmp(keyinfo->seg, info->first_mbr_key, k,
113  info->last_rkey_length, search_flag))
114  {
115  uchar *after_key = rt_PAGE_NEXT_KEY(k, k_len, nod_flag);
116  info->lastpos = _mi_dpos(info, 0, after_key);
117  info->lastkey_length = k_len + info->s->base.rec_reflength;
118  memcpy(info->lastkey, k, info->lastkey_length);
119  info->rtree_recursion_depth = level;
120  *saved_key = (uint) (last - page_buf);
121 
122  if (after_key < last)
123  {
124  info->int_keypos = info->buff;
125  info->int_maxpos = info->buff + (last - after_key);
126  memcpy(info->buff, after_key, last - after_key);
127  info->buff_used = 0;
128  }
129  else
130  {
131  info->buff_used = 1;
132  }
133 
134  res = 0;
135  goto ok;
136  }
137  }
138  }
139  info->lastpos = HA_OFFSET_ERROR;
140  my_errno = HA_ERR_KEY_NOT_FOUND;
141  res = 1;
142 
143 ok:
144  my_afree((uchar*)page_buf);
145  return res;
146 
147 err1:
148  my_afree((uchar*)page_buf);
149  info->lastpos = HA_OFFSET_ERROR;
150  return -1;
151 }
152 
153 
154 /*
155  Find first key in r-tree according to search_flag condition
156 
157  SYNOPSIS
158  rtree_find_first()
159  info Handler to MyISAM file
160  uint keynr Key number to use
161  key Key to search for
162  key_length Length of 'key'
163  search_flag Bitmap of flags how to do the search
164 
165  RETURN
166  -1 Error
167  0 Found
168  1 Not found
169 */
170 
171 int rtree_find_first(MI_INFO *info, uint keynr, uchar *key, uint key_length,
172  uint search_flag)
173 {
174  my_off_t root;
175  uint nod_cmp_flag;
176  MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
177 
178  if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
179  {
180  my_errno= HA_ERR_END_OF_FILE;
181  return -1;
182  }
183 
184  /*
185  Save searched key, include data pointer.
186  The data pointer is required if the search_flag contains MBR_DATA.
187  (minimum bounding rectangle)
188  */
189  memcpy(info->first_mbr_key, key, keyinfo->keylength);
190  info->last_rkey_length = key_length;
191 
192  info->rtree_recursion_depth = -1;
193  info->buff_used = 1;
194 
195  nod_cmp_flag = ((search_flag & (MBR_EQUAL | MBR_WITHIN)) ?
196  MBR_WITHIN : MBR_INTERSECT);
197  return rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag, root, 0);
198 }
199 
200 
201 /*
202  Find next key in r-tree according to search_flag condition
203 
204  SYNOPSIS
205  rtree_find_next()
206  info Handler to MyISAM file
207  uint keynr Key number to use
208  search_flag Bitmap of flags how to do the search
209 
210  RETURN
211  -1 Error
212  0 Found
213  1 Not found
214 */
215 
216 int rtree_find_next(MI_INFO *info, uint keynr, uint search_flag)
217 {
218  my_off_t root;
219  uint nod_cmp_flag;
220  MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
221 
222  if (info->update & HA_STATE_DELETED)
223  return rtree_find_first(info, keynr, info->lastkey, info->lastkey_length,
224  search_flag);
225 
226  if (!info->buff_used)
227  {
228  uchar *key= info->int_keypos;
229 
230  while (key < info->int_maxpos)
231  {
232  if (!rtree_key_cmp(keyinfo->seg, info->first_mbr_key, key,
233  info->last_rkey_length, search_flag))
234  {
235  uchar *after_key = key + keyinfo->keylength;
236 
237  info->lastpos= _mi_dpos(info, 0, after_key);
238  memcpy(info->lastkey, key, info->lastkey_length);
239 
240  if (after_key < info->int_maxpos)
241  info->int_keypos= after_key;
242  else
243  info->buff_used= 1;
244  return 0;
245  }
246  key+= keyinfo->keylength;
247  }
248  }
249  if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
250  {
251  my_errno= HA_ERR_END_OF_FILE;
252  return -1;
253  }
254 
255  nod_cmp_flag = ((search_flag & (MBR_EQUAL | MBR_WITHIN)) ?
256  MBR_WITHIN : MBR_INTERSECT);
257  return rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag, root, 0);
258 }
259 
260 
261 /*
262  Get next key in r-tree recursively
263 
264  NOTES
265  Used in rtree_get_first() and rtree_get_next()
266 
267  RETURN
268  -1 Error
269  0 Found
270  1 Not found
271 */
272 
273 static int rtree_get_req(MI_INFO *info, MI_KEYDEF *keyinfo, uint key_length,
274  my_off_t page, int level)
275 {
276  uchar *k;
277  uchar *last;
278  uint nod_flag;
279  int res;
280  uchar *page_buf;
281  uint k_len;
282  uint *saved_key = (uint*) (info->rtree_recursion_state) + level;
283 
284  if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
285  return -1;
286  if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0))
287  goto err1;
288  nod_flag = mi_test_if_nod(page_buf);
289 
290  k_len = keyinfo->keylength - info->s->base.rec_reflength;
291 
292  if(info->rtree_recursion_depth >= level)
293  {
294  k = page_buf + *saved_key;
295  if (!nod_flag)
296  {
297  /* Only leaf pages contain data references. */
298  /* Need to check next key with data reference. */
299  k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag);
300  }
301  }
302  else
303  {
304  k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
305  }
306  last = rt_PAGE_END(page_buf);
307 
308  for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag))
309  {
310  if (nod_flag)
311  {
312  /* this is an internal node in the tree */
313  switch ((res = rtree_get_req(info, keyinfo, key_length,
314  _mi_kpos(nod_flag, k), level + 1)))
315  {
316  case 0: /* found - exit from recursion */
317  *saved_key = (uint) (k - page_buf);
318  goto ok;
319  case 1: /* not found - continue searching */
320  info->rtree_recursion_depth = level;
321  break;
322  default:
323  case -1: /* error */
324  goto err1;
325  }
326  }
327  else
328  {
329  /* this is a leaf */
330  uchar *after_key = rt_PAGE_NEXT_KEY(k, k_len, nod_flag);
331  info->lastpos = _mi_dpos(info, 0, after_key);
332  info->lastkey_length = k_len + info->s->base.rec_reflength;
333  memcpy(info->lastkey, k, info->lastkey_length);
334 
335  info->rtree_recursion_depth = level;
336  *saved_key = (uint) (k - page_buf);
337 
338  if (after_key < last)
339  {
340  info->int_keypos = (uchar*)saved_key;
341  memcpy(info->buff, page_buf, keyinfo->block_length);
342  info->int_maxpos = rt_PAGE_END(info->buff);
343  info->buff_used = 0;
344  }
345  else
346  {
347  info->buff_used = 1;
348  }
349 
350  res = 0;
351  goto ok;
352  }
353  }
354  info->lastpos = HA_OFFSET_ERROR;
355  my_errno = HA_ERR_KEY_NOT_FOUND;
356  res = 1;
357 
358 ok:
359  my_afree((uchar*)page_buf);
360  return res;
361 
362 err1:
363  my_afree((uchar*)page_buf);
364  info->lastpos = HA_OFFSET_ERROR;
365  return -1;
366 }
367 
368 
369 /*
370  Get first key in r-tree
371 
372  RETURN
373  -1 Error
374  0 Found
375  1 Not found
376 */
377 
378 int rtree_get_first(MI_INFO *info, uint keynr, uint key_length)
379 {
380  my_off_t root;
381  MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
382 
383  if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
384  {
385  my_errno= HA_ERR_END_OF_FILE;
386  return -1;
387  }
388 
389  info->rtree_recursion_depth = -1;
390  info->buff_used = 1;
391 
392  return rtree_get_req(info, keyinfo, key_length, root, 0);
393 }
394 
395 
396 /*
397  Get next key in r-tree
398 
399  RETURN
400  -1 Error
401  0 Found
402  1 Not found
403 */
404 
405 int rtree_get_next(MI_INFO *info, uint keynr, uint key_length)
406 {
407  my_off_t root= info->s->state.key_root[keynr];
408  MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
409 
410  if (root == HA_OFFSET_ERROR)
411  {
412  my_errno= HA_ERR_END_OF_FILE;
413  return -1;
414  }
415 
416  if (!info->buff_used && !info->page_changed)
417  {
418  uint k_len = keyinfo->keylength - info->s->base.rec_reflength;
419  /* rt_PAGE_NEXT_KEY(info->int_keypos) */
420  uchar *key = info->buff + *(int*)info->int_keypos + k_len +
421  info->s->base.rec_reflength;
422  /* rt_PAGE_NEXT_KEY(key) */
423  uchar *after_key = key + k_len + info->s->base.rec_reflength;
424 
425  info->lastpos = _mi_dpos(info, 0, after_key);
426  info->lastkey_length = k_len + info->s->base.rec_reflength;
427  memcpy(info->lastkey, key, k_len + info->s->base.rec_reflength);
428 
429  *(uint*)info->int_keypos = (uint) (key - info->buff);
430  if (after_key >= info->int_maxpos)
431  {
432  info->buff_used = 1;
433  }
434 
435  return 0;
436  }
437 
438  return rtree_get_req(info, keyinfo, key_length, root, 0);
439 }
440 
441 
442 /*
443  Choose non-leaf better key for insertion
444 */
445 
446 #ifdef PICK_BY_PERIMETER
447 static uchar *rtree_pick_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
448  uint key_length, uchar *page_buf, uint nod_flag)
449 {
450  double increase;
451  double best_incr = DBL_MAX;
452  double perimeter;
453  double best_perimeter;
454  uchar *best_key;
455  uchar *k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
456  uchar *last = rt_PAGE_END(page_buf);
457 
458  LINT_INIT(best_perimeter);
459  LINT_INIT(best_key);
460 
461  for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag))
462  {
463  if ((increase = rtree_perimeter_increase(keyinfo->seg, k, key, key_length,
464  &perimeter)) == -1)
465  return NULL;
466  if ((increase < best_incr)||
467  (increase == best_incr && perimeter < best_perimeter))
468  {
469  best_key = k;
470  best_perimeter= perimeter;
471  best_incr = increase;
472  }
473  }
474  return best_key;
475 }
476 
477 #endif /*PICK_BY_PERIMETER*/
478 
479 #ifdef PICK_BY_AREA
480 static uchar *rtree_pick_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
481  uint key_length, uchar *page_buf, uint nod_flag)
482 {
483  double increase;
484  double UNINIT_VAR(best_incr);
485  double area;
486  double UNINIT_VAR(best_area);
487  uchar *best_key= NULL;
488  uchar *k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
489  uchar *last = rt_PAGE_END(page_buf);
490 
491  for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag))
492  {
493  /* The following is safe as -1.0 is an exact number */
494  if ((increase = rtree_area_increase(keyinfo->seg, k, key, key_length,
495  &area)) == -1.0)
496  return NULL;
497  /* The following should be safe, even if we compare doubles */
498  if (!best_key || increase < best_incr ||
499  ((increase == best_incr) && (area < best_area)))
500  {
501  best_key = k;
502  best_area = area;
503  best_incr = increase;
504  }
505  }
506  return best_key;
507 }
508 
509 #endif /*PICK_BY_AREA*/
510 
511 /*
512  Go down and insert key into tree
513 
514  RETURN
515  -1 Error
516  0 Child was not split
517  1 Child was split
518 */
519 
520 static int rtree_insert_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
521  uint key_length, my_off_t page, my_off_t *new_page,
522  int ins_level, int level)
523 {
524  uchar *k;
525  uint nod_flag;
526  uchar *page_buf;
527  int res;
528  DBUG_ENTER("rtree_insert_req");
529 
530  if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length +
531  MI_MAX_KEY_BUFF)))
532  {
533  my_errno = HA_ERR_OUT_OF_MEM;
534  DBUG_RETURN(-1); /* purecov: inspected */
535  }
536  if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0))
537  goto err1;
538  nod_flag = mi_test_if_nod(page_buf);
539  DBUG_PRINT("rtree", ("page: %lu level: %d ins_level: %d nod_flag: %u",
540  (ulong) page, level, ins_level, nod_flag));
541 
542  if ((ins_level == -1 && nod_flag) || /* key: go down to leaf */
543  (ins_level > -1 && ins_level > level)) /* branch: go down to ins_level */
544  {
545  if ((k = rtree_pick_key(info, keyinfo, key, key_length, page_buf,
546  nod_flag)) == NULL)
547  goto err1;
548  switch ((res = rtree_insert_req(info, keyinfo, key, key_length,
549  _mi_kpos(nod_flag, k), new_page, ins_level, level + 1)))
550  {
551  case 0: /* child was not split */
552  {
553  rtree_combine_rect(keyinfo->seg, k, key, k, key_length);
554  if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
555  goto err1;
556  goto ok;
557  }
558  case 1: /* child was split */
559  {
560  uchar *new_key = page_buf + keyinfo->block_length + nod_flag;
561  /* set proper MBR for key */
562  if (rtree_set_key_mbr(info, keyinfo, k, key_length,
563  _mi_kpos(nod_flag, k)))
564  goto err1;
565  /* add new key for new page */
566  _mi_kpointer(info, new_key - nod_flag, *new_page);
567  if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, *new_page))
568  goto err1;
569  res = rtree_add_key(info, keyinfo, new_key, key_length,
570  page_buf, new_page);
571  if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
572  goto err1;
573  goto ok;
574  }
575  default:
576  case -1: /* error */
577  {
578  goto err1;
579  }
580  }
581  }
582  else
583  {
584  res = rtree_add_key(info, keyinfo, key, key_length, page_buf, new_page);
585  if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
586  goto err1;
587  goto ok;
588  }
589 
590 ok:
591  my_afree((uchar*)page_buf);
592  DBUG_RETURN(res);
593 
594 err1:
595  my_afree((uchar*)page_buf);
596  DBUG_RETURN(-1); /* purecov: inspected */
597 }
598 
599 
600 /*
601  Insert key into the tree
602 
603  RETURN
604  -1 Error
605  0 Root was not split
606  1 Root was split
607 */
608 
609 static int rtree_insert_level(MI_INFO *info, uint keynr, uchar *key,
610  uint key_length, int ins_level)
611 {
612  my_off_t old_root;
613  MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
614  int res;
615  my_off_t new_page;
616  DBUG_ENTER("rtree_insert_level");
617 
618  if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
619  {
620  if ((old_root = _mi_new(info, keyinfo, DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
621  DBUG_RETURN(-1);
622  info->buff_used = 1;
623  mi_putint(info->buff, 2, 0);
624  res = rtree_add_key(info, keyinfo, key, key_length, info->buff, NULL);
625  if (_mi_write_keypage(info, keyinfo, old_root, DFLT_INIT_HITS, info->buff))
626  DBUG_RETURN(1);
627  info->s->state.key_root[keynr] = old_root;
628  DBUG_RETURN(res);
629  }
630 
631  switch ((res = rtree_insert_req(info, keyinfo, key, key_length,
632  old_root, &new_page, ins_level, 0)))
633  {
634  case 0: /* root was not split */
635  {
636  break;
637  }
638  case 1: /* root was split, grow a new root */
639  {
640  uchar *new_root_buf= info->buff + info->s->base.max_key_block_length;
641  my_off_t new_root;
642  uchar *new_key;
643  uint nod_flag = info->s->base.key_reflength;
644 
645  DBUG_PRINT("rtree", ("root was split, grow a new root"));
646 
647  mi_putint(new_root_buf, 2, nod_flag);
648  if ((new_root = _mi_new(info, keyinfo, DFLT_INIT_HITS)) ==
649  HA_OFFSET_ERROR)
650  goto err1;
651 
652  new_key = new_root_buf + keyinfo->block_length + nod_flag;
653 
654  _mi_kpointer(info, new_key - nod_flag, old_root);
655  if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, old_root))
656  goto err1;
657  if (rtree_add_key(info, keyinfo, new_key, key_length, new_root_buf, NULL)
658  == -1)
659  goto err1;
660  _mi_kpointer(info, new_key - nod_flag, new_page);
661  if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, new_page))
662  goto err1;
663  if (rtree_add_key(info, keyinfo, new_key, key_length, new_root_buf, NULL)
664  == -1)
665  goto err1;
666  if (_mi_write_keypage(info, keyinfo, new_root,
667  DFLT_INIT_HITS, new_root_buf))
668  goto err1;
669  info->s->state.key_root[keynr] = new_root;
670  DBUG_PRINT("rtree", ("new root page: %lu level: %d nod_flag: %u",
671  (ulong) new_root, 0, mi_test_if_nod(new_root_buf)));
672 
673  break;
674 err1:
675  DBUG_RETURN(-1); /* purecov: inspected */
676  }
677  default:
678  case -1: /* error */
679  {
680  break;
681  }
682  }
683  DBUG_RETURN(res);
684 }
685 
686 
687 /*
688  Insert key into the tree - interface function
689 
690  RETURN
691  -1 Error
692  0 OK
693 */
694 
695 int rtree_insert(MI_INFO *info, uint keynr, uchar *key, uint key_length)
696 {
697  DBUG_ENTER("rtree_insert");
698  DBUG_RETURN((!key_length ||
699  (rtree_insert_level(info, keynr, key, key_length, -1) == -1)) ?
700  -1 : 0);
701 }
702 
703 
704 /*
705  Fill reinsert page buffer
706 
707  RETURN
708  -1 Error
709  0 OK
710 */
711 
712 static int rtree_fill_reinsert_list(stPageList *ReinsertList, my_off_t page,
713  int level)
714 {
715  DBUG_ENTER("rtree_fill_reinsert_list");
716  DBUG_PRINT("rtree", ("page: %lu level: %d", (ulong) page, level));
717  if (ReinsertList->n_pages == ReinsertList->m_pages)
718  {
719  ReinsertList->m_pages += REINSERT_BUFFER_INC;
720  if (!(ReinsertList->pages = (stPageLevel*)my_realloc((uchar*)ReinsertList->pages,
721  ReinsertList->m_pages * sizeof(stPageLevel), MYF(MY_ALLOW_ZERO_PTR))))
722  goto err1;
723  }
724  /* save page to ReinsertList */
725  ReinsertList->pages[ReinsertList->n_pages].offs = page;
726  ReinsertList->pages[ReinsertList->n_pages].level = level;
727  ReinsertList->n_pages++;
728  DBUG_RETURN(0);
729 
730 err1:
731  DBUG_RETURN(-1); /* purecov: inspected */
732 }
733 
734 
735 /*
736  Go down and delete key from the tree
737 
738  RETURN
739  -1 Error
740  0 Deleted
741  1 Not found
742  2 Empty leaf
743 */
744 
745 static int rtree_delete_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
746  uint key_length, my_off_t page, uint *page_size,
747  stPageList *ReinsertList, int level)
748 {
749  uchar *k;
750  uchar *last;
751  ulong i;
752  uint nod_flag;
753  uchar *page_buf;
754  int res;
755  DBUG_ENTER("rtree_delete_req");
756 
757  if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
758  {
759  my_errno = HA_ERR_OUT_OF_MEM;
760  DBUG_RETURN(-1); /* purecov: inspected */
761  }
762  if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0))
763  goto err1;
764  nod_flag = mi_test_if_nod(page_buf);
765  DBUG_PRINT("rtree", ("page: %lu level: %d nod_flag: %u",
766  (ulong) page, level, nod_flag));
767 
768  k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
769  last = rt_PAGE_END(page_buf);
770 
771  for (i = 0; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag), ++i)
772  {
773  if (nod_flag)
774  {
775  /* not leaf */
776  if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN))
777  {
778  switch ((res = rtree_delete_req(info, keyinfo, key, key_length,
779  _mi_kpos(nod_flag, k), page_size, ReinsertList, level + 1)))
780  {
781  case 0: /* deleted */
782  {
783  /* test page filling */
784  if (*page_size + key_length >= rt_PAGE_MIN_SIZE(keyinfo->block_length))
785  {
786  /* OK */
787  /* Calculate a new key value (MBR) for the shrinked block. */
788  if (rtree_set_key_mbr(info, keyinfo, k, key_length,
789  _mi_kpos(nod_flag, k)))
790  goto err1;
791  if (_mi_write_keypage(info, keyinfo, page,
792  DFLT_INIT_HITS, page_buf))
793  goto err1;
794  }
795  else
796  {
797  /*
798  Too small: delete key & add it descendant to reinsert list.
799  Store position and level of the block so that it can be
800  accessed later for inserting the remaining keys.
801  */
802  DBUG_PRINT("rtree", ("too small. move block to reinsert list"));
803  if (rtree_fill_reinsert_list(ReinsertList, _mi_kpos(nod_flag, k),
804  level + 1))
805  goto err1;
806  /*
807  Delete the key that references the block. This makes the
808  block disappear from the index. Hence we need to insert
809  its remaining keys later. Note: if the block is a branch
810  block, we do not only remove this block, but the whole
811  subtree. So we need to re-insert its keys on the same
812  level later to reintegrate the subtrees.
813  */
814  rtree_delete_key(info, page_buf, k, key_length, nod_flag);
815  if (_mi_write_keypage(info, keyinfo, page,
816  DFLT_INIT_HITS, page_buf))
817  goto err1;
818  *page_size = mi_getint(page_buf);
819  }
820 
821  goto ok;
822  }
823  case 1: /* not found - continue searching */
824  {
825  break;
826  }
827  case 2: /* vacuous case: last key in the leaf */
828  {
829  rtree_delete_key(info, page_buf, k, key_length, nod_flag);
830  if (_mi_write_keypage(info, keyinfo, page,
831  DFLT_INIT_HITS, page_buf))
832  goto err1;
833  *page_size = mi_getint(page_buf);
834  res = 0;
835  goto ok;
836  }
837  default: /* error */
838  case -1:
839  {
840  goto err1;
841  }
842  }
843  }
844  }
845  else
846  {
847  /* leaf */
848  if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_EQUAL | MBR_DATA))
849  {
850  rtree_delete_key(info, page_buf, k, key_length, nod_flag);
851  *page_size = mi_getint(page_buf);
852  if (*page_size == 2)
853  {
854  /* last key in the leaf */
855  res = 2;
856  if (_mi_dispose(info, keyinfo, page, DFLT_INIT_HITS))
857  goto err1;
858  }
859  else
860  {
861  res = 0;
862  if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
863  goto err1;
864  }
865  goto ok;
866  }
867  }
868  }
869  res = 1;
870 
871 ok:
872  my_afree((uchar*)page_buf);
873  DBUG_RETURN(res);
874 
875 err1:
876  my_afree((uchar*)page_buf);
877  DBUG_RETURN(-1); /* purecov: inspected */
878 }
879 
880 
881 /*
882  Delete key - interface function
883 
884  RETURN
885  -1 Error
886  0 Deleted
887 */
888 
889 int rtree_delete(MI_INFO *info, uint keynr, uchar *key, uint key_length)
890 {
891  uint page_size;
892  stPageList ReinsertList;
893  my_off_t old_root;
894  MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
895  DBUG_ENTER("rtree_delete");
896 
897  if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
898  {
899  my_errno= HA_ERR_END_OF_FILE;
900  DBUG_RETURN(-1); /* purecov: inspected */
901  }
902  DBUG_PRINT("rtree", ("starting deletion at root page: %lu",
903  (ulong) old_root));
904 
905  ReinsertList.pages = NULL;
906  ReinsertList.n_pages = 0;
907  ReinsertList.m_pages = 0;
908 
909  switch (rtree_delete_req(info, keyinfo, key, key_length, old_root,
910  &page_size, &ReinsertList, 0))
911  {
912  case 2: /* empty */
913  {
914  info->s->state.key_root[keynr] = HA_OFFSET_ERROR;
915  DBUG_RETURN(0);
916  }
917  case 0: /* deleted */
918  {
919  uint nod_flag;
920  ulong i;
921  for (i = 0; i < ReinsertList.n_pages; ++i)
922  {
923  uchar *page_buf;
924  uchar *k;
925  uchar *last;
926 
927  if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
928  {
929  my_errno = HA_ERR_OUT_OF_MEM;
930  goto err1;
931  }
932  if (!_mi_fetch_keypage(info, keyinfo, ReinsertList.pages[i].offs,
933  DFLT_INIT_HITS, page_buf, 0))
934  goto err1;
935  nod_flag = mi_test_if_nod(page_buf);
936  DBUG_PRINT("rtree", ("reinserting keys from "
937  "page: %lu level: %d nod_flag: %u",
938  (ulong) ReinsertList.pages[i].offs,
939  ReinsertList.pages[i].level, nod_flag));
940 
941  k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
942  last = rt_PAGE_END(page_buf);
943  for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag))
944  {
945  int res;
946  if ((res= rtree_insert_level(info, keynr, k, key_length,
947  ReinsertList.pages[i].level)) == -1)
948  {
949  my_afree((uchar*)page_buf);
950  goto err1;
951  }
952  if (res)
953  {
954  ulong j;
955  DBUG_PRINT("rtree", ("root has been split, adjust levels"));
956  for (j= i; j < ReinsertList.n_pages; j++)
957  {
958  ReinsertList.pages[j].level++;
959  DBUG_PRINT("rtree", ("keys from page: %lu now level: %d",
960  (ulong) ReinsertList.pages[i].offs,
961  ReinsertList.pages[i].level));
962  }
963  }
964  }
965  my_afree((uchar*)page_buf);
966  if (_mi_dispose(info, keyinfo, ReinsertList.pages[i].offs,
967  DFLT_INIT_HITS))
968  goto err1;
969  }
970  if (ReinsertList.pages)
971  my_free(ReinsertList.pages);
972 
973  /* check for redundant root (not leaf, 1 child) and eliminate */
974  if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
975  goto err1;
976  if (!_mi_fetch_keypage(info, keyinfo, old_root, DFLT_INIT_HITS,
977  info->buff, 0))
978  goto err1;
979  nod_flag = mi_test_if_nod(info->buff);
980  page_size = mi_getint(info->buff);
981  if (nod_flag && (page_size == 2 + key_length + nod_flag))
982  {
983  my_off_t new_root = _mi_kpos(nod_flag,
984  rt_PAGE_FIRST_KEY(info->buff, nod_flag));
985  if (_mi_dispose(info, keyinfo, old_root, DFLT_INIT_HITS))
986  goto err1;
987  info->s->state.key_root[keynr] = new_root;
988  }
989  info->update= HA_STATE_DELETED;
990  DBUG_RETURN(0);
991 
992 err1:
993  DBUG_RETURN(-1); /* purecov: inspected */
994  }
995  case 1: /* not found */
996  {
997  my_errno = HA_ERR_KEY_NOT_FOUND;
998  DBUG_RETURN(-1); /* purecov: inspected */
999  }
1000  default:
1001  case -1: /* error */
1002  {
1003  DBUG_RETURN(-1); /* purecov: inspected */
1004  }
1005  }
1006 }
1007 
1008 
1009 /*
1010  Estimate number of suitable keys in the tree
1011 
1012  RETURN
1013  estimated value
1014 */
1015 
1016 ha_rows rtree_estimate(MI_INFO *info, uint keynr, uchar *key,
1017  uint key_length, uint flag)
1018 {
1019  MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
1020  my_off_t root;
1021  uint i = 0;
1022  uchar *k;
1023  uchar *last;
1024  uint nod_flag;
1025  uchar *page_buf;
1026  uint k_len;
1027  double area = 0;
1028  ha_rows res = 0;
1029 
1030  if (flag & MBR_DISJOINT)
1031  return info->state->records;
1032 
1033  if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
1034  return HA_POS_ERROR;
1035  if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
1036  return HA_POS_ERROR;
1037  if (!_mi_fetch_keypage(info, keyinfo, root, DFLT_INIT_HITS, page_buf, 0))
1038  goto err1;
1039  nod_flag = mi_test_if_nod(page_buf);
1040 
1041  k_len = keyinfo->keylength - info->s->base.rec_reflength;
1042 
1043  k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
1044  last = rt_PAGE_END(page_buf);
1045 
1046  for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag), ++i)
1047  {
1048  if (nod_flag)
1049  {
1050  double k_area = rtree_rect_volume(keyinfo->seg, k, key_length);
1051 
1052  /* The following should be safe, even if we compare doubles */
1053  if (k_area == 0)
1054  {
1055  if (flag & (MBR_CONTAIN | MBR_INTERSECT))
1056  {
1057  area += 1;
1058  }
1059  else if (flag & (MBR_WITHIN | MBR_EQUAL))
1060  {
1061  if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN))
1062  area += 1;
1063  }
1064  else
1065  goto err1;
1066  }
1067  else
1068  {
1069  if (flag & (MBR_CONTAIN | MBR_INTERSECT))
1070  {
1071  area += rtree_overlapping_area(keyinfo->seg, key, k, key_length) /
1072  k_area;
1073  }
1074  else if (flag & (MBR_WITHIN | MBR_EQUAL))
1075  {
1076  if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN))
1077  area += rtree_rect_volume(keyinfo->seg, key, key_length) /
1078  k_area;
1079  }
1080  else
1081  goto err1;
1082  }
1083  }
1084  else
1085  {
1086  if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, flag))
1087  ++res;
1088  }
1089  }
1090  if (nod_flag)
1091  {
1092  if (i)
1093  res = (ha_rows) (area / i * info->state->records);
1094  else
1095  res = HA_POS_ERROR;
1096  }
1097 
1098  my_afree((uchar*)page_buf);
1099  return res;
1100 
1101 err1:
1102  my_afree((uchar*)page_buf);
1103  return HA_POS_ERROR;
1104 }
1105 
1106 #endif /*HAVE_RTREE_KEYS*/
1107