int rtree_add_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, uint key_length, uchar *page_buf, my_off_t *new_page) { uint page_size = mi_getint(page_buf); uint nod_flag = mi_test_if_nod(page_buf); DBUG_ENTER("rtree_add_key"); if (page_size + key_length + info->s->base.rec_reflength <= keyinfo->block_length) { /* split won't be necessary */ if (nod_flag) { /* save key */ DBUG_ASSERT(_mi_kpos(nod_flag, key) < info->state->key_file_length); memcpy(rt_PAGE_END(page_buf), key - nod_flag, key_length + nod_flag); page_size += key_length + nod_flag; } else { /* save key */ DBUG_ASSERT(_mi_dpos(info, nod_flag, key + key_length + info->s->base.rec_reflength) < info->state->data_file_length + info->s->base.pack_reclength); memcpy(rt_PAGE_END(page_buf), key, key_length + info->s->base.rec_reflength); page_size += key_length + info->s->base.rec_reflength; } mi_putint(page_buf, page_size, nod_flag); DBUG_RETURN(0); } DBUG_RETURN((rtree_split_page(info, keyinfo, page_buf, key, key_length, new_page) ? -1 : 1)); }
int rtree_delete(MI_INFO *info, uint keynr, uchar *key, uint key_length) { uint page_size; stPageList ReinsertList; my_off_t old_root; MI_KEYDEF *keyinfo = info->s->keyinfo + keynr; DBUG_ENTER("rtree_delete"); if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) { my_errno= HA_ERR_END_OF_FILE; DBUG_RETURN(-1); /* purecov: inspected */ } DBUG_PRINT("rtree", ("starting deletion at root page: %lu", (ulong) old_root)); ReinsertList.pages = NULL; ReinsertList.n_pages = 0; ReinsertList.m_pages = 0; switch (rtree_delete_req(info, keyinfo, key, key_length, old_root, &page_size, &ReinsertList, 0)) { case 2: /* empty */ { info->s->state.key_root[keynr] = HA_OFFSET_ERROR; DBUG_RETURN(0); } case 0: /* deleted */ { uint nod_flag; ulong i; for (i = 0; i < ReinsertList.n_pages; ++i) { uchar *page_buf; uchar *k; uchar *last; if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length))) { my_errno = HA_ERR_OUT_OF_MEM; goto err1; } if (!_mi_fetch_keypage(info, keyinfo, ReinsertList.pages[i].offs, DFLT_INIT_HITS, page_buf, 0)) goto err1; nod_flag = mi_test_if_nod(page_buf); DBUG_PRINT("rtree", ("reinserting keys from " "page: %lu level: %d nod_flag: %u", (ulong) ReinsertList.pages[i].offs, ReinsertList.pages[i].level, nod_flag)); k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); last = rt_PAGE_END(page_buf); for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag)) { int res; if ((res= rtree_insert_level(info, keynr, k, key_length, ReinsertList.pages[i].level)) == -1) { my_afree((uchar*)page_buf); goto err1; } if (res) { ulong j; DBUG_PRINT("rtree", ("root has been split, adjust levels")); for (j= i; j < ReinsertList.n_pages; j++) { ReinsertList.pages[j].level++; DBUG_PRINT("rtree", ("keys from page: %lu now level: %d", (ulong) ReinsertList.pages[i].offs, ReinsertList.pages[i].level)); } } } my_afree((uchar*)page_buf); if (_mi_dispose(info, keyinfo, ReinsertList.pages[i].offs, DFLT_INIT_HITS)) goto err1; } if (ReinsertList.pages) my_free((uchar*) ReinsertList.pages, MYF(0)); /* check for redundant root (not leaf, 1 child) and eliminate */ if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) goto err1; if (!_mi_fetch_keypage(info, keyinfo, old_root, DFLT_INIT_HITS, info->buff, 0)) goto err1; nod_flag = mi_test_if_nod(info->buff); page_size = mi_getint(info->buff); if (nod_flag && (page_size == 2 + key_length + nod_flag)) { my_off_t new_root = _mi_kpos(nod_flag, rt_PAGE_FIRST_KEY(info->buff, nod_flag)); if (_mi_dispose(info, keyinfo, old_root, DFLT_INIT_HITS)) goto err1; info->s->state.key_root[keynr] = new_root; } info->update= HA_STATE_DELETED; DBUG_RETURN(0); err1: DBUG_RETURN(-1); /* purecov: inspected */ } case 1: /* not found */ { my_errno = HA_ERR_KEY_NOT_FOUND; DBUG_RETURN(-1); /* purecov: inspected */ } default: case -1: /* error */ { DBUG_RETURN(-1); /* purecov: inspected */ } } }
static int rtree_insert_level(MI_INFO *info, uint keynr, uchar *key, uint key_length, int ins_level) { my_off_t old_root; MI_KEYDEF *keyinfo = info->s->keyinfo + keynr; int res; my_off_t new_page; DBUG_ENTER("rtree_insert_level"); if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) { if ((old_root = _mi_new(info, keyinfo, DFLT_INIT_HITS)) == HA_OFFSET_ERROR) DBUG_RETURN(-1); info->buff_used = 1; mi_putint(info->buff, 2, 0); res = rtree_add_key(info, keyinfo, key, key_length, info->buff, NULL); if (_mi_write_keypage(info, keyinfo, old_root, DFLT_INIT_HITS, info->buff)) DBUG_RETURN(1); info->s->state.key_root[keynr] = old_root; DBUG_RETURN(res); } switch ((res = rtree_insert_req(info, keyinfo, key, key_length, old_root, &new_page, ins_level, 0))) { case 0: /* root was not split */ { break; } case 1: /* root was split, grow a new root */ { uchar *new_root_buf= info->buff + info->s->base.max_key_block_length; my_off_t new_root; uchar *new_key; uint nod_flag = info->s->base.key_reflength; DBUG_PRINT("rtree", ("root was split, grow a new root")); mi_putint(new_root_buf, 2, nod_flag); if ((new_root = _mi_new(info, keyinfo, DFLT_INIT_HITS)) == HA_OFFSET_ERROR) goto err1; new_key = new_root_buf + keyinfo->block_length + nod_flag; _mi_kpointer(info, new_key - nod_flag, old_root); if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, old_root)) goto err1; if (rtree_add_key(info, keyinfo, new_key, key_length, new_root_buf, NULL) == -1) goto err1; _mi_kpointer(info, new_key - nod_flag, new_page); if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, new_page)) goto err1; if (rtree_add_key(info, keyinfo, new_key, key_length, new_root_buf, NULL) == -1) goto err1; if (_mi_write_keypage(info, keyinfo, new_root, DFLT_INIT_HITS, new_root_buf)) goto err1; info->s->state.key_root[keynr] = new_root; DBUG_PRINT("rtree", ("new root page: %lu level: %d nod_flag: %u", (ulong) new_root, 0, mi_test_if_nod(new_root_buf))); break; err1: DBUG_RETURN(-1); /* purecov: inspected */ } default: case -1: /* error */ { break; } } DBUG_RETURN(res); }
static int rtree_delete_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, uint key_length, my_off_t page, uint *page_size, stPageList *ReinsertList, int level) { uchar *k; uchar *last; ulong i; uint nod_flag; uchar *page_buf; int res; DBUG_ENTER("rtree_delete_req"); if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length))) { my_errno = HA_ERR_OUT_OF_MEM; DBUG_RETURN(-1); /* purecov: inspected */ } if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0)) goto err1; nod_flag = mi_test_if_nod(page_buf); DBUG_PRINT("rtree", ("page: %lu level: %d nod_flag: %u", (ulong) page, level, nod_flag)); k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); last = rt_PAGE_END(page_buf); for (i = 0; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag), ++i) { if (nod_flag) { /* not leaf */ if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN)) { switch ((res = rtree_delete_req(info, keyinfo, key, key_length, _mi_kpos(nod_flag, k), page_size, ReinsertList, level + 1))) { case 0: /* deleted */ { /* test page filling */ if (*page_size + key_length >= rt_PAGE_MIN_SIZE(keyinfo->block_length)) { /* OK */ /* Calculate a new key value (MBR) for the shrinked block. */ if (rtree_set_key_mbr(info, keyinfo, k, key_length, _mi_kpos(nod_flag, k))) goto err1; if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf)) goto err1; } else { /* Too small: delete key & add it descendant to reinsert list. Store position and level of the block so that it can be accessed later for inserting the remaining keys. */ DBUG_PRINT("rtree", ("too small. move block to reinsert list")); if (rtree_fill_reinsert_list(ReinsertList, _mi_kpos(nod_flag, k), level + 1)) goto err1; /* Delete the key that references the block. This makes the block disappear from the index. Hence we need to insert its remaining keys later. Note: if the block is a branch block, we do not only remove this block, but the whole subtree. So we need to re-insert its keys on the same level later to reintegrate the subtrees. */ rtree_delete_key(info, page_buf, k, key_length, nod_flag); if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf)) goto err1; *page_size = mi_getint(page_buf); } goto ok; } case 1: /* not found - continue searching */ { break; } case 2: /* vacuous case: last key in the leaf */ { rtree_delete_key(info, page_buf, k, key_length, nod_flag); if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf)) goto err1; *page_size = mi_getint(page_buf); res = 0; goto ok; } default: /* error */ case -1: { goto err1; } } } } else { /* leaf */ if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_EQUAL | MBR_DATA)) { rtree_delete_key(info, page_buf, k, key_length, nod_flag); *page_size = mi_getint(page_buf); if (*page_size == 2) { /* last key in the leaf */ res = 2; if (_mi_dispose(info, keyinfo, page, DFLT_INIT_HITS)) goto err1; } else { res = 0; if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf)) goto err1; } goto ok; } } } res = 1; ok: my_afree((uchar*)page_buf); DBUG_RETURN(res); err1: my_afree((uchar*)page_buf); DBUG_RETURN(-1); /* purecov: inspected */ }
static int rtree_insert_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, uint key_length, my_off_t page, my_off_t *new_page, int ins_level, int level) { uchar *k; uint nod_flag; uchar *page_buf; int res; DBUG_ENTER("rtree_insert_req"); if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length + MI_MAX_KEY_BUFF))) { my_errno = HA_ERR_OUT_OF_MEM; DBUG_RETURN(-1); /* purecov: inspected */ } if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0)) goto err1; nod_flag = mi_test_if_nod(page_buf); DBUG_PRINT("rtree", ("page: %lu level: %d ins_level: %d nod_flag: %u", (ulong) page, level, ins_level, nod_flag)); if ((ins_level == -1 && nod_flag) || /* key: go down to leaf */ (ins_level > -1 && ins_level > level)) /* branch: go down to ins_level */ { if ((k = rtree_pick_key(info, keyinfo, key, key_length, page_buf, nod_flag)) == NULL) goto err1; switch ((res = rtree_insert_req(info, keyinfo, key, key_length, _mi_kpos(nod_flag, k), new_page, ins_level, level + 1))) { case 0: /* child was not split */ { rtree_combine_rect(keyinfo->seg, k, key, k, key_length); if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf)) goto err1; goto ok; } case 1: /* child was split */ { uchar *new_key = page_buf + keyinfo->block_length + nod_flag; /* set proper MBR for key */ if (rtree_set_key_mbr(info, keyinfo, k, key_length, _mi_kpos(nod_flag, k))) goto err1; /* add new key for new page */ _mi_kpointer(info, new_key - nod_flag, *new_page); if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, *new_page)) goto err1; res = rtree_add_key(info, keyinfo, new_key, key_length, page_buf, new_page); if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf)) goto err1; goto ok; } default: case -1: /* error */ { goto err1; } } } else { res = rtree_add_key(info, keyinfo, key, key_length, page_buf, new_page); if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf)) goto err1; goto ok; } ok: my_afree((uchar*)page_buf); DBUG_RETURN(res); err1: my_afree((uchar*)page_buf); DBUG_RETURN(-1); /* purecov: inspected */ }
static int rtree_find_req(MI_INFO *info, MI_KEYDEF *keyinfo, uint search_flag, uint nod_cmp_flag, my_off_t page, int level) { uchar *k; uchar *last; uint nod_flag; int res; uchar *page_buf; int k_len; uint *saved_key = (uint*) (info->rtree_recursion_state) + level; if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length))) { my_errno = HA_ERR_OUT_OF_MEM; return -1; } if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0)) goto err1; nod_flag = mi_test_if_nod(page_buf); k_len = keyinfo->keylength - info->s->base.rec_reflength; if(info->rtree_recursion_depth >= level) { k = page_buf + *saved_key; } else { k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); } last = rt_PAGE_END(page_buf); for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag)) { if (nod_flag) { /* this is an internal node in the tree */ if (!(res = rtree_key_cmp(keyinfo->seg, info->first_mbr_key, k, info->last_rkey_length, nod_cmp_flag))) { switch ((res = rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag, _mi_kpos(nod_flag, k), level + 1))) { case 0: /* found - exit from recursion */ *saved_key = (uint) (k - page_buf); goto ok; case 1: /* not found - continue searching */ info->rtree_recursion_depth = level; break; default: /* error */ case -1: goto err1; } } } else { /* this is a leaf */ if (!rtree_key_cmp(keyinfo->seg, info->first_mbr_key, k, info->last_rkey_length, search_flag)) { uchar *after_key = rt_PAGE_NEXT_KEY(k, k_len, nod_flag); info->lastpos = _mi_dpos(info, 0, after_key); info->lastkey_length = k_len + info->s->base.rec_reflength; memcpy(info->lastkey, k, info->lastkey_length); info->rtree_recursion_depth = level; *saved_key = (uint) (last - page_buf); if (after_key < last) { info->int_keypos = info->buff; info->int_maxpos = info->buff + (last - after_key); memcpy(info->buff, after_key, last - after_key); info->buff_used = 0; } else { info->buff_used = 1; } res = 0; goto ok; } } } info->lastpos = HA_OFFSET_ERROR; my_errno = HA_ERR_KEY_NOT_FOUND; res = 1; ok: my_afree((uchar*)page_buf); return res; err1: my_afree((uchar*)page_buf); info->lastpos = HA_OFFSET_ERROR; return -1; }
int mi_preload(MI_INFO *info, ulonglong key_map, my_bool ignore_leaves) { uint i; ulong length, block_length= 0; uchar *buff= NULL; MYISAM_SHARE* share= info->s; uint keys= share->state.header.keys; MI_KEYDEF *keyinfo= share->keyinfo; my_off_t key_file_length= share->state.state.key_file_length; my_off_t pos= share->base.keystart; DBUG_ENTER("mi_preload"); if (!keys || !mi_is_any_key_active(key_map) || key_file_length == pos) DBUG_RETURN(0); block_length= keyinfo[0].block_length; if (ignore_leaves) { /* Check whether all indexes use the same block size */ for (i= 1 ; i < keys ; i++) { if (keyinfo[i].block_length != block_length) DBUG_RETURN(my_errno= HA_ERR_NON_UNIQUE_BLOCK_SIZE); } } else block_length= share->key_cache->key_cache_block_size; length= info->preload_buff_size/block_length * block_length; set_if_bigger(length, block_length); if (!(buff= (uchar *) my_malloc(length, MYF(MY_WME)))) DBUG_RETURN(my_errno= HA_ERR_OUT_OF_MEM); if (flush_key_blocks(share->key_cache,share->kfile, FLUSH_RELEASE)) goto err; do { /* Read the next block of index file into the preload buffer */ if ((my_off_t) length > (key_file_length-pos)) length= (ulong) (key_file_length-pos); if (mysql_file_pread(share->kfile, (uchar*) buff, length, pos, MYF(MY_FAE|MY_FNABP))) goto err; if (ignore_leaves) { uchar *end= buff+length; do { if (mi_test_if_nod(buff)) { if (key_cache_insert(share->key_cache, share->kfile, pos, DFLT_INIT_HITS, (uchar*) buff, block_length)) goto err; } pos+= block_length; } while ((buff+= block_length) != end); buff= end-length; } else { if (key_cache_insert(share->key_cache, share->kfile, pos, DFLT_INIT_HITS, (uchar*) buff, length)) goto err; pos+= length; } } while (pos != key_file_length); my_free(buff); DBUG_RETURN(0); err: my_free(buff); DBUG_RETURN(my_errno= errno); }
ha_rows rtree_estimate(MI_INFO *info, uint keynr, uchar *key, uint key_length, uint flag) { MI_KEYDEF *keyinfo = info->s->keyinfo + keynr; my_off_t root; uint i = 0; uchar *k; uchar *last; uint nod_flag; uchar *page_buf; uint k_len; double area = 0; ha_rows res = 0; if (flag & MBR_DISJOINT) return info->state->records; if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) return HA_POS_ERROR; if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length))) return HA_POS_ERROR; if (!_mi_fetch_keypage(info, keyinfo, root, DFLT_INIT_HITS, page_buf, 0)) goto err1; nod_flag = mi_test_if_nod(page_buf); k_len = keyinfo->keylength - info->s->base.rec_reflength; k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); last = rt_PAGE_END(page_buf); for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag), ++i) { if (nod_flag) { double k_area = rtree_rect_volume(keyinfo->seg, k, key_length); /* The following should be safe, even if we compare doubles */ if (k_area == 0) { if (flag & (MBR_CONTAIN | MBR_INTERSECT)) { area += 1; } else if (flag & (MBR_WITHIN | MBR_EQUAL)) { if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN)) area += 1; } else goto err1; } else { if (flag & (MBR_CONTAIN | MBR_INTERSECT)) { area += rtree_overlapping_area(keyinfo->seg, key, k, key_length) / k_area; } else if (flag & (MBR_WITHIN | MBR_EQUAL)) { if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN)) area += rtree_rect_volume(keyinfo->seg, key, key_length) / k_area; } else goto err1; } } else { if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, flag)) ++res; } } if (nod_flag) { if (i) res = (ha_rows) (area / i * info->state->records); else res = HA_POS_ERROR; } my_afree((uchar*)page_buf); return res; err1: my_afree((uchar*)page_buf); return HA_POS_ERROR; }
static int rtree_get_req(MI_INFO *info, MI_KEYDEF *keyinfo, uint key_length, my_off_t page, int level) { uchar *k; uchar *last; uint nod_flag; int res; uchar *page_buf; uint k_len; uint *saved_key = (uint*) (info->rtree_recursion_state) + level; if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length))) return -1; if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0)) goto err1; nod_flag = mi_test_if_nod(page_buf); k_len = keyinfo->keylength - info->s->base.rec_reflength; if(info->rtree_recursion_depth >= level) { k = page_buf + *saved_key; if (!nod_flag) { /* Only leaf pages contain data references. */ /* Need to check next key with data reference. */ k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag); } } else { k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); } last = rt_PAGE_END(page_buf); for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag)) { if (nod_flag) { /* this is an internal node in the tree */ switch ((res = rtree_get_req(info, keyinfo, key_length, _mi_kpos(nod_flag, k), level + 1))) { case 0: /* found - exit from recursion */ *saved_key = k - page_buf; goto ok; case 1: /* not found - continue searching */ info->rtree_recursion_depth = level; break; default: case -1: /* error */ goto err1; } } else { /* this is a leaf */ uchar *after_key = rt_PAGE_NEXT_KEY(k, k_len, nod_flag); info->lastpos = _mi_dpos(info, 0, after_key); info->lastkey_length = k_len + info->s->base.rec_reflength; memcpy(info->lastkey, k, info->lastkey_length); info->rtree_recursion_depth = level; *saved_key = k - page_buf; if (after_key < last) { info->int_keypos = (uchar*)saved_key; memcpy(info->buff, page_buf, keyinfo->block_length); info->int_maxpos = rt_PAGE_END(info->buff); info->buff_used = 0; } else { info->buff_used = 1; } res = 0; goto ok; } } info->lastpos = HA_OFFSET_ERROR; my_errno = HA_ERR_KEY_NOT_FOUND; res = 1; ok: my_afree((uchar*)page_buf); return res; err1: my_afree((uchar*)page_buf); info->lastpos = HA_OFFSET_ERROR; return -1; }
int rtree_split_page(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uchar *key, uint key_length, my_off_t *new_page_offs) { int n1, n2; /* Number of items in groups */ SplitStruct *task; SplitStruct *cur; SplitStruct *stop; double *coord_buf; double *next_coord; int n_dim; uchar *source_cur, *cur1, *cur2; uchar *new_page= info->buff; int err_code= 0; uint nod_flag= mi_test_if_nod(page); uint full_length= key_length + (nod_flag ? nod_flag : info->s->base.rec_reflength); int max_keys= (mi_getint(page)-2) / (full_length); DBUG_ENTER("rtree_split_page"); DBUG_PRINT("rtree", ("splitting block")); n_dim = keyinfo->keysegs / 2; if (!(coord_buf= (double*) my_alloca(n_dim * 2 * sizeof(double) * (max_keys + 1 + 4) + sizeof(SplitStruct) * (max_keys + 1)))) DBUG_RETURN(-1); /* purecov: inspected */ task= (SplitStruct *)(coord_buf + n_dim * 2 * (max_keys + 1 + 4)); next_coord = coord_buf; stop = task + max_keys; source_cur = rt_PAGE_FIRST_KEY(page, nod_flag); for (cur = task; cur < stop; ++cur, source_cur = rt_PAGE_NEXT_KEY(source_cur, key_length, nod_flag)) { cur->coords = reserve_coords(&next_coord, n_dim); cur->key = source_cur; rtree_d_mbr(keyinfo->seg, source_cur, key_length, cur->coords); } cur->coords = reserve_coords(&next_coord, n_dim); rtree_d_mbr(keyinfo->seg, key, key_length, cur->coords); cur->key = key; if (split_rtree_node(task, max_keys + 1, mi_getint(page) + full_length + 2, full_length, rt_PAGE_MIN_SIZE(keyinfo->block_length), 2, 2, &next_coord, n_dim)) { err_code = 1; goto split_err; } info->buff_used= 1; stop = task + (max_keys + 1); cur1 = rt_PAGE_FIRST_KEY(page, nod_flag); cur2 = rt_PAGE_FIRST_KEY(new_page, nod_flag); n1= n2 = 0; for (cur = task; cur < stop; ++cur) { uchar *to; if (cur->n_node == 1) { to = cur1; cur1 = rt_PAGE_NEXT_KEY(cur1, key_length, nod_flag); ++n1; } else { to = cur2; cur2 = rt_PAGE_NEXT_KEY(cur2, key_length, nod_flag); ++n2; } if (to != cur->key) memcpy(to - nod_flag, cur->key - nod_flag, full_length); } mi_putint(page, 2 + n1 * full_length, nod_flag); mi_putint(new_page, 2 + n2 * full_length, nod_flag); if ((*new_page_offs= _mi_new(info, keyinfo, DFLT_INIT_HITS)) == HA_OFFSET_ERROR) err_code= -1; else err_code= _mi_write_keypage(info, keyinfo, *new_page_offs, DFLT_INIT_HITS, new_page); DBUG_PRINT("rtree", ("split new block: %lu", (ulong) *new_page_offs)); split_err: my_afree((uchar*) coord_buf); DBUG_RETURN(err_code); }
/* Calculates key page total MBR = MBR(key1) + MBR(key2) + ... */ int rtree_page_mbr(MI_INFO *info, HA_KEYSEG *keyseg, uchar *page_buf, uchar *c, uint key_length) { uint inc = 0; uint k_len = key_length; uint nod_flag = mi_test_if_nod(page_buf); uchar *k; uchar *last = rt_PAGE_END(page_buf); for (; (int)key_length > 0; keyseg += 2) { key_length -= keyseg->length * 2; /* Handle NULL part */ if (keyseg->null_bit) { return 1; } k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); switch ((enum ha_base_keytype) keyseg->type) { case HA_KEYTYPE_INT8: RT_PAGE_MBR_KORR(int8, mi_sint1korr, mi_int1store, 1); break; case HA_KEYTYPE_BINARY: RT_PAGE_MBR_KORR(uint8, mi_uint1korr, mi_int1store, 1); break; case HA_KEYTYPE_SHORT_INT: RT_PAGE_MBR_KORR(int16, mi_sint2korr, mi_int2store, 2); break; case HA_KEYTYPE_USHORT_INT: RT_PAGE_MBR_KORR(uint16, mi_uint2korr, mi_int2store, 2); break; case HA_KEYTYPE_INT24: RT_PAGE_MBR_KORR(int32, mi_sint3korr, mi_int3store, 3); break; case HA_KEYTYPE_UINT24: RT_PAGE_MBR_KORR(uint32, mi_uint3korr, mi_int3store, 3); break; case HA_KEYTYPE_LONG_INT: RT_PAGE_MBR_KORR(int32, mi_sint4korr, mi_int4store, 4); break; case HA_KEYTYPE_ULONG_INT: RT_PAGE_MBR_KORR(uint32, mi_uint4korr, mi_int4store, 4); break; #ifdef HAVE_LONG_LONG case HA_KEYTYPE_LONGLONG: RT_PAGE_MBR_KORR(longlong, mi_sint8korr, mi_int8store, 8); break; case HA_KEYTYPE_ULONGLONG: RT_PAGE_MBR_KORR(ulonglong, mi_uint8korr, mi_int8store, 8); break; #endif case HA_KEYTYPE_FLOAT: RT_PAGE_MBR_GET(float, mi_float4get, mi_float4store, 4); break; case HA_KEYTYPE_DOUBLE: RT_PAGE_MBR_GET(double, mi_float8get, mi_float8store, 8); break; case HA_KEYTYPE_END: return 0; default: return 1; } } return 0; }
static int w_search(register MI_INFO * info, register MI_KEYDEF * keyinfo, uchar * key, uint key_length, my_off_t page, uchar * father_buff, uchar * father_keypos, my_off_t father_page, my_bool insert_last) { int error , flag; uint comp_flag, nod_flag; uchar *temp_buff, *keypos; uchar keybuff [MI_MAX_KEY_BUFF]; my_bool was_last_key; my_off_t next_page; DBUG_ENTER("w_search"); DBUG_PRINT("enter", ("page: %ld", page)); if (keyinfo->flag & HA_SORT_ALLOWS_SAME) comp_flag = SEARCH_BIGGER; /* Put after same key */ else if (keyinfo->flag & HA_NOSAME) comp_flag = SEARCH_FIND | SEARCH_UPDATE; /* No dupplicates */ else comp_flag = SEARCH_SAME; /* Keys in rec-pos order */ if (!(temp_buff = (uchar *) my_alloca((uint) keyinfo->block_length + MI_MAX_KEY_BUFF * 2))) DBUG_RETURN(-1); if (!_mi_fetch_keypage(info, keyinfo, page, temp_buff, 0)) goto err; flag = (*keyinfo->bin_search) (info, keyinfo, temp_buff, key, key_length, comp_flag, &keypos, keybuff, &was_last_key); nod_flag = mi_test_if_nod(temp_buff); if (flag == 0) { uint tmp_key_length; my_errno = HA_ERR_FOUND_DUPP_KEY; /* get position to record with duplicated key */ tmp_key_length = (*keyinfo->get_key) (keyinfo, nod_flag, &keypos, keybuff); if (tmp_key_length) info->dupp_key_pos = _mi_dpos(info, 0, keybuff + tmp_key_length); else info->dupp_key_pos = HA_OFFSET_ERROR; my_afree((byte *) temp_buff); DBUG_RETURN(-1); } if (flag == MI_FOUND_WRONG_KEY) DBUG_RETURN(-1); if (!was_last_key) insert_last = 0; next_page = _mi_kpos(nod_flag, keypos); if (next_page == HA_OFFSET_ERROR || (error = w_search(info, keyinfo, key, key_length, next_page, temp_buff, keypos, page, insert_last)) > 0) { error = _mi_insert(info, keyinfo, key, temp_buff, keypos, keybuff, father_buff, father_keypos, father_page, insert_last); if (_mi_write_keypage(info, keyinfo, page, temp_buff)) goto err; } my_afree((byte *) temp_buff); DBUG_RETURN(error); err: my_afree((byte *) temp_buff); DBUG_PRINT("exit", ("Error: %d", my_errno)); DBUG_RETURN(-1); } /* w_search */
int _mi_insert(register MI_INFO * info, register MI_KEYDEF * keyinfo, uchar * key, uchar * anc_buff, uchar * key_pos, uchar * key_buff, uchar * father_buff, uchar * father_key_pos, my_off_t father_page, my_bool insert_last) { uint a_length , nod_flag; int t_length; uchar *endpos, *prev_key; MI_KEY_PARAM s_temp; DBUG_ENTER("_mi_insert"); DBUG_PRINT("enter", ("key_pos: %lx", key_pos)); DBUG_EXECUTE("key", _mi_print_key(DBUG_FILE, keyinfo->seg, key, USE_WHOLE_KEY); ); nod_flag = mi_test_if_nod(anc_buff); a_length = mi_getint(anc_buff); endpos = anc_buff + a_length; prev_key = (key_pos == anc_buff + 2 + nod_flag ? (uchar *) 0 : key_buff); t_length = (*keyinfo->pack_key) (keyinfo, nod_flag, (key_pos == endpos ? (uchar *) 0 : key_pos), prev_key, prev_key, key, &s_temp); #ifndef DBUG_OFF if (key_pos != anc_buff + 2 + nod_flag && (keyinfo->flag & (HA_BINARY_PACK_KEY | HA_PACK_KEY))) DBUG_DUMP("prev_key", (byte *) key_buff, _mi_keylength(keyinfo, key_buff)); if (keyinfo->flag & HA_PACK_KEY) { DBUG_PRINT("test", ("t_length: %d ref_len: %d", t_length, s_temp.ref_length)); DBUG_PRINT("test", ("n_ref_len: %d n_length: %d key: %lx",