16 #include "myisamdef.h"
18 #ifdef HAVE_RTREE_KEYS
24 #define REINSERT_BUFFER_INC 10
28 typedef struct st_page_level
34 typedef struct st_page_list
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)
63 uint *saved_key = (uint*) (info->rtree_recursion_state) +
level;
65 if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
67 my_errno = HA_ERR_OUT_OF_MEM;
70 if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0))
72 nod_flag = mi_test_if_nod(page_buf);
74 k_len = keyinfo->keylength - info->s->base.rec_reflength;
76 if(info->rtree_recursion_depth >= level)
78 k = page_buf + *saved_key;
82 k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
84 last = rt_PAGE_END(page_buf);
86 for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag))
91 if (!(res = rtree_key_cmp(keyinfo->seg, info->first_mbr_key, k,
92 info->last_rkey_length, nod_cmp_flag)))
94 switch ((res = rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag,
95 _mi_kpos(nod_flag, k), level + 1)))
98 *saved_key = (uint) (k - page_buf);
101 info->rtree_recursion_depth =
level;
112 if (!rtree_key_cmp(keyinfo->seg, info->first_mbr_key, k,
113 info->last_rkey_length, search_flag))
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);
122 if (after_key < last)
124 info->int_keypos = info->buff;
125 info->int_maxpos = info->buff + (last - after_key);
126 memcpy(info->buff, after_key, last - after_key);
139 info->lastpos = HA_OFFSET_ERROR;
140 my_errno = HA_ERR_KEY_NOT_FOUND;
144 my_afree((uchar*)page_buf);
148 my_afree((uchar*)page_buf);
149 info->lastpos = HA_OFFSET_ERROR;
171 int rtree_find_first(
MI_INFO *info, uint keynr, uchar *key, uint key_length,
176 MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
178 if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
180 my_errno= HA_ERR_END_OF_FILE;
189 memcpy(info->first_mbr_key, key, keyinfo->keylength);
190 info->last_rkey_length = key_length;
192 info->rtree_recursion_depth = -1;
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);
216 int rtree_find_next(
MI_INFO *info, uint keynr, uint search_flag)
220 MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
222 if (info->update & HA_STATE_DELETED)
223 return rtree_find_first(info, keynr, info->lastkey, info->lastkey_length,
226 if (!info->buff_used)
228 uchar *key= info->int_keypos;
230 while (key < info->int_maxpos)
232 if (!rtree_key_cmp(keyinfo->seg, info->first_mbr_key, key,
233 info->last_rkey_length, search_flag))
235 uchar *after_key = key + keyinfo->keylength;
237 info->lastpos= _mi_dpos(info, 0, after_key);
238 memcpy(info->lastkey, key, info->lastkey_length);
240 if (after_key < info->int_maxpos)
241 info->int_keypos= after_key;
246 key+= keyinfo->keylength;
249 if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
251 my_errno= HA_ERR_END_OF_FILE;
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);
273 static int rtree_get_req(
MI_INFO *info,
MI_KEYDEF *keyinfo, uint key_length,
274 my_off_t page,
int level)
282 uint *saved_key = (uint*) (info->rtree_recursion_state) +
level;
284 if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
286 if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0))
288 nod_flag = mi_test_if_nod(page_buf);
290 k_len = keyinfo->keylength - info->s->base.rec_reflength;
292 if(info->rtree_recursion_depth >= level)
294 k = page_buf + *saved_key;
299 k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag);
304 k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
306 last = rt_PAGE_END(page_buf);
308 for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag))
313 switch ((res = rtree_get_req(info, keyinfo, key_length,
314 _mi_kpos(nod_flag, k), level + 1)))
317 *saved_key = (uint) (k - page_buf);
320 info->rtree_recursion_depth =
level;
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);
335 info->rtree_recursion_depth =
level;
336 *saved_key = (uint) (k - page_buf);
338 if (after_key < last)
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);
354 info->lastpos = HA_OFFSET_ERROR;
355 my_errno = HA_ERR_KEY_NOT_FOUND;
359 my_afree((uchar*)page_buf);
363 my_afree((uchar*)page_buf);
364 info->lastpos = HA_OFFSET_ERROR;
378 int rtree_get_first(
MI_INFO *info, uint keynr, uint key_length)
381 MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
383 if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
385 my_errno= HA_ERR_END_OF_FILE;
389 info->rtree_recursion_depth = -1;
392 return rtree_get_req(info, keyinfo, key_length, root, 0);
405 int rtree_get_next(
MI_INFO *info, uint keynr, uint key_length)
407 my_off_t root= info->s->state.key_root[keynr];
408 MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
410 if (root == HA_OFFSET_ERROR)
412 my_errno= HA_ERR_END_OF_FILE;
416 if (!info->buff_used && !info->page_changed)
418 uint k_len = keyinfo->keylength - info->s->base.rec_reflength;
420 uchar *key = info->buff + *(
int*)info->int_keypos + k_len +
421 info->s->base.rec_reflength;
423 uchar *after_key = key + k_len + info->s->base.rec_reflength;
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);
429 *(uint*)info->int_keypos = (uint) (key - info->buff);
430 if (after_key >= info->int_maxpos)
438 return rtree_get_req(info, keyinfo, key_length, root, 0);
446 #ifdef PICK_BY_PERIMETER
448 uint key_length, uchar *page_buf, uint nod_flag)
451 double best_incr = DBL_MAX;
453 double best_perimeter;
455 uchar *k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
456 uchar *last = rt_PAGE_END(page_buf);
458 LINT_INIT(best_perimeter);
461 for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag))
463 if ((increase = rtree_perimeter_increase(keyinfo->seg, k, key, key_length,
466 if ((increase < best_incr)||
467 (increase == best_incr && perimeter < best_perimeter))
470 best_perimeter= perimeter;
471 best_incr = increase;
481 uint key_length, uchar *page_buf, uint nod_flag)
484 double UNINIT_VAR(best_incr);
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);
491 for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag))
494 if ((increase = rtree_area_increase(keyinfo->seg, k, key, key_length,
498 if (!best_key || increase < best_incr ||
499 ((increase == best_incr) && (area < best_area)))
503 best_incr = increase;
521 uint key_length, my_off_t page, my_off_t *new_page,
522 int ins_level,
int level)
528 DBUG_ENTER(
"rtree_insert_req");
530 if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length +
533 my_errno = HA_ERR_OUT_OF_MEM;
536 if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0))
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));
542 if ((ins_level == -1 && nod_flag) ||
543 (ins_level > -1 && ins_level > level))
545 if ((k = rtree_pick_key(info, keyinfo, key, key_length, page_buf,
548 switch ((res = rtree_insert_req(info, keyinfo, key, key_length,
549 _mi_kpos(nod_flag, k), new_page, ins_level, level + 1)))
553 rtree_combine_rect(keyinfo->seg, k, key, k, key_length);
554 if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
560 uchar *new_key = page_buf + keyinfo->block_length + nod_flag;
562 if (rtree_set_key_mbr(info, keyinfo, k, key_length,
563 _mi_kpos(nod_flag, k)))
566 _mi_kpointer(info, new_key - nod_flag, *new_page);
567 if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, *new_page))
569 res = rtree_add_key(info, keyinfo, new_key, key_length,
571 if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
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))
591 my_afree((uchar*)page_buf);
595 my_afree((uchar*)page_buf);
609 static int rtree_insert_level(
MI_INFO *info, uint keynr, uchar *key,
610 uint key_length,
int ins_level)
613 MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
616 DBUG_ENTER(
"rtree_insert_level");
618 if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
620 if ((old_root = _mi_new(info, keyinfo, DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
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))
627 info->s->state.key_root[keynr] = old_root;
631 switch ((res = rtree_insert_req(info, keyinfo, key, key_length,
632 old_root, &new_page, ins_level, 0)))
640 uchar *new_root_buf= info->buff + info->s->base.max_key_block_length;
643 uint nod_flag = info->s->base.key_reflength;
645 DBUG_PRINT(
"rtree", (
"root was split, grow a new root"));
647 mi_putint(new_root_buf, 2, nod_flag);
648 if ((new_root = _mi_new(info, keyinfo, DFLT_INIT_HITS)) ==
652 new_key = new_root_buf + keyinfo->block_length + nod_flag;
654 _mi_kpointer(info, new_key - nod_flag, old_root);
655 if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, old_root))
657 if (rtree_add_key(info, keyinfo, new_key, key_length, new_root_buf, NULL)
660 _mi_kpointer(info, new_key - nod_flag, new_page);
661 if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, new_page))
663 if (rtree_add_key(info, keyinfo, new_key, key_length, new_root_buf, NULL)
666 if (_mi_write_keypage(info, keyinfo, new_root,
667 DFLT_INIT_HITS, new_root_buf))
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)));
695 int rtree_insert(
MI_INFO *info, uint keynr, uchar *key, uint key_length)
697 DBUG_ENTER(
"rtree_insert");
698 DBUG_RETURN((!key_length ||
699 (rtree_insert_level(info, keynr, key, key_length, -1) == -1)) ?
712 static int rtree_fill_reinsert_list(stPageList *ReinsertList, my_off_t page,
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)
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))))
725 ReinsertList->pages[ReinsertList->n_pages].offs =
page;
726 ReinsertList->pages[ReinsertList->n_pages].level =
level;
727 ReinsertList->n_pages++;
746 uint key_length, my_off_t page, uint *page_size,
747 stPageList *ReinsertList,
int level)
755 DBUG_ENTER(
"rtree_delete_req");
757 if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
759 my_errno = HA_ERR_OUT_OF_MEM;
762 if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0))
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));
768 k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
769 last = rt_PAGE_END(page_buf);
771 for (i = 0; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag), ++
i)
776 if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN))
778 switch ((res = rtree_delete_req(info, keyinfo, key, key_length,
779 _mi_kpos(nod_flag, k), page_size, ReinsertList, level + 1)))
784 if (*page_size + key_length >= rt_PAGE_MIN_SIZE(keyinfo->block_length))
788 if (rtree_set_key_mbr(info, keyinfo, k, key_length,
789 _mi_kpos(nod_flag, k)))
791 if (_mi_write_keypage(info, keyinfo, page,
792 DFLT_INIT_HITS, page_buf))
802 DBUG_PRINT(
"rtree", (
"too small. move block to reinsert list"));
803 if (rtree_fill_reinsert_list(ReinsertList, _mi_kpos(nod_flag, k),
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))
818 *page_size = mi_getint(page_buf);
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))
833 *page_size = mi_getint(page_buf);
848 if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_EQUAL | MBR_DATA))
850 rtree_delete_key(info, page_buf, k, key_length, nod_flag);
851 *page_size = mi_getint(page_buf);
856 if (_mi_dispose(info, keyinfo, page, DFLT_INIT_HITS))
862 if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
872 my_afree((uchar*)page_buf);
876 my_afree((uchar*)page_buf);
889 int rtree_delete(
MI_INFO *info, uint keynr, uchar *key, uint key_length)
892 stPageList ReinsertList;
894 MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
895 DBUG_ENTER(
"rtree_delete");
897 if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
899 my_errno= HA_ERR_END_OF_FILE;
902 DBUG_PRINT(
"rtree", (
"starting deletion at root page: %lu",
905 ReinsertList.pages = NULL;
906 ReinsertList.n_pages = 0;
907 ReinsertList.m_pages = 0;
909 switch (rtree_delete_req(info, keyinfo, key, key_length, old_root,
910 &page_size, &ReinsertList, 0))
914 info->s->state.key_root[keynr] = HA_OFFSET_ERROR;
921 for (i = 0; i < ReinsertList.n_pages; ++
i)
927 if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
929 my_errno = HA_ERR_OUT_OF_MEM;
932 if (!_mi_fetch_keypage(info, keyinfo, ReinsertList.pages[i].offs,
933 DFLT_INIT_HITS, page_buf, 0))
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));
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))
946 if ((res= rtree_insert_level(info, keynr, k, key_length,
947 ReinsertList.pages[i].level)) == -1)
949 my_afree((uchar*)page_buf);
955 DBUG_PRINT(
"rtree", (
"root has been split, adjust levels"));
956 for (j= i; j < ReinsertList.n_pages; j++)
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));
965 my_afree((uchar*)page_buf);
966 if (_mi_dispose(info, keyinfo, ReinsertList.pages[i].offs,
970 if (ReinsertList.pages)
971 my_free(ReinsertList.pages);
974 if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
976 if (!_mi_fetch_keypage(info, keyinfo, old_root, DFLT_INIT_HITS,
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))
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))
987 info->s->state.key_root[keynr] = new_root;
989 info->update= HA_STATE_DELETED;
997 my_errno = HA_ERR_KEY_NOT_FOUND;
1016 ha_rows rtree_estimate(
MI_INFO *info, uint keynr, uchar *key,
1017 uint key_length, uint flag)
1019 MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
1030 if (flag & MBR_DISJOINT)
1031 return info->state->records;
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))
1039 nod_flag = mi_test_if_nod(page_buf);
1041 k_len = keyinfo->keylength - info->s->base.rec_reflength;
1043 k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
1044 last = rt_PAGE_END(page_buf);
1046 for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag), ++
i)
1050 double k_area = rtree_rect_volume(keyinfo->seg, k, key_length);
1055 if (flag & (MBR_CONTAIN | MBR_INTERSECT))
1059 else if (flag & (MBR_WITHIN | MBR_EQUAL))
1061 if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN))
1069 if (flag & (MBR_CONTAIN | MBR_INTERSECT))
1071 area += rtree_overlapping_area(keyinfo->seg, key, k, key_length) /
1074 else if (flag & (MBR_WITHIN | MBR_EQUAL))
1076 if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN))
1077 area += rtree_rect_volume(keyinfo->seg, key, key_length) /
1086 if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, flag))
1093 res = (ha_rows) (area / i * info->state->records);
1098 my_afree((uchar*)page_buf);
1102 my_afree((uchar*)page_buf);
1103 return HA_POS_ERROR;