~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2002-2006 MySQL AB & Ramil Kalimullin
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 = 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 = 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 = 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 = 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[keynr], 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;
408
  MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
409
410
  if (!info->buff_used)
411
  {
412
    uint k_len = keyinfo->keylength - info->s->base.rec_reflength;
413
    /* rt_PAGE_NEXT_KEY(info->int_keypos) */
414
    uchar *key = info->buff + *(int*)info->int_keypos + k_len + 
415
                 info->s->base.rec_reflength;
416
    /* rt_PAGE_NEXT_KEY(key) */
417
    uchar *after_key = key + k_len + info->s->base.rec_reflength; 
418
419
    info->lastpos = _mi_dpos(info, 0, after_key);
420
    info->lastkey_length = k_len + info->s->base.rec_reflength;
421
    memcpy(info->lastkey, key, k_len + info->s->base.rec_reflength);
422
423
    *(int*)info->int_keypos = key - info->buff;
424
    if (after_key >= info->int_maxpos)
425
    {
426
      info->buff_used = 1;
427
    }
428
429
    return 0;
430
  }
431
  else
432
  {
433
    if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
434
    {
435
      my_errno= HA_ERR_END_OF_FILE;
436
      return -1;
437
    }
438
  
439
    return rtree_get_req(info, &keyinfo[keynr], key_length, root, 0);
440
  }
441
}
442
443
444
/*
445
  Choose non-leaf better key for insertion
446
*/
447
448
#ifdef PICK_BY_PERIMETER
449
static uchar *rtree_pick_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, 
450
			     uint key_length, uchar *page_buf, uint nod_flag)
451
{
452
  double increase;
453
  double best_incr = DBL_MAX;
454
  double perimeter;
455
  double best_perimeter;
456
  uchar *best_key;
457
  uchar *k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
458
  uchar *last = rt_PAGE_END(page_buf);
459
460
  LINT_INIT(best_perimeter);
461
  LINT_INIT(best_key);
462
463
  for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag))
464
  {
465
    if ((increase = rtree_perimeter_increase(keyinfo->seg, k, key, key_length,
466
					     &perimeter)) == -1)
467
      return NULL;
468
    if ((increase < best_incr)||
469
	(increase == best_incr && perimeter < best_perimeter))
470
    {
471
      best_key = k;
472
      best_perimeter= perimeter;
473
      best_incr = increase;
474
    }
475
  }
476
  return best_key;
477
}
478
479
#endif /*PICK_BY_PERIMETER*/
480
481
#ifdef PICK_BY_AREA
482
static uchar *rtree_pick_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, 
483
			     uint key_length, uchar *page_buf, uint nod_flag)
484
{
485
  double increase;
486
  double best_incr;
487
  double area;
488
  double best_area;
489
  uchar *best_key= NULL;
490
  uchar *k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
491
  uchar *last = rt_PAGE_END(page_buf);
492
493
  LINT_INIT(best_area);
494
  LINT_INIT(best_key);
495
  LINT_INIT(best_incr);
496
497
  for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag))
498
  {
499
    /* The following is safe as -1.0 is an exact number */
500
    if ((increase = rtree_area_increase(keyinfo->seg, k, key, key_length, 
501
                                        &area)) == -1.0)
502
      return NULL;
503
    /* The following should be safe, even if we compare doubles */
504
    if (!best_key || increase < best_incr ||
505
        ((increase == best_incr) && (area < best_area)))
506
    {
507
      best_key = k;
508
      best_area = area;
509
      best_incr = increase;
510
    }
511
  }
512
  return best_key;
513
}
514
515
#endif /*PICK_BY_AREA*/
516
517
/*
518
  Go down and insert key into tree
519
520
  RETURN
521
    -1	Error
522
    0	Child was not split
523
    1	Child was split
524
*/
525
526
static int rtree_insert_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, 
527
                            uint key_length, my_off_t page, my_off_t *new_page, 
528
                            int ins_level, int level)
529
{
530
  uchar *k;
531
  uint nod_flag;
532
  uchar *page_buf;
533
  int res;
534
  DBUG_ENTER("rtree_insert_req");
535
536
  if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length + 
537
                                     MI_MAX_KEY_BUFF)))
538
  {
539
    my_errno = HA_ERR_OUT_OF_MEM;
540
    DBUG_RETURN(-1); /* purecov: inspected */
541
  }
542
  if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0))
543
    goto err1;
544
  nod_flag = mi_test_if_nod(page_buf);
545
  DBUG_PRINT("rtree", ("page: %lu  level: %d  ins_level: %d  nod_flag: %u",
546
                       (ulong) page, level, ins_level, nod_flag));
547
548
  if ((ins_level == -1 && nod_flag) ||       /* key: go down to leaf */
549
      (ins_level > -1 && ins_level > level)) /* branch: go down to ins_level */
550
  { 
551
    if ((k = rtree_pick_key(info, keyinfo, key, key_length, page_buf, 
552
                             nod_flag)) == NULL)
553
      goto err1;
554
    switch ((res = rtree_insert_req(info, keyinfo, key, key_length, 
555
                     _mi_kpos(nod_flag, k), new_page, ins_level, level + 1)))
556
    {
557
      case 0: /* child was not split */
558
      {
559
        rtree_combine_rect(keyinfo->seg, k, key, k, key_length);
560
        if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
561
          goto err1;
562
        goto ok;
563
      }
564
      case 1: /* child was split */
565
      {
566
        uchar *new_key = page_buf + keyinfo->block_length + nod_flag;
567
        /* set proper MBR for key */
568
        if (rtree_set_key_mbr(info, keyinfo, k, key_length, 
569
                            _mi_kpos(nod_flag, k)))
570
          goto err1;
571
        /* add new key for new page */
572
        _mi_kpointer(info, new_key - nod_flag, *new_page);
573
        if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, *new_page))
574
          goto err1;
575
        res = rtree_add_key(info, keyinfo, new_key, key_length, 
576
                           page_buf, new_page);
577
        if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
578
          goto err1;
579
        goto ok;
580
      }
581
      default:
582
      case -1: /* error */
583
      {
584
        goto err1;
585
      }
586
    }
587
  }
588
  else
589
  { 
590
    res = rtree_add_key(info, keyinfo, key, key_length, page_buf, new_page);
591
    if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
592
      goto err1;
593
    goto ok;
594
  }
595
596
ok:
597
  my_afree((uchar*)page_buf);
598
  DBUG_RETURN(res);
599
600
err1:
601
  my_afree((uchar*)page_buf);
602
  DBUG_RETURN(-1); /* purecov: inspected */
603
}
604
605
606
/*
607
  Insert key into the tree
608
609
  RETURN
610
    -1	Error
611
    0	Root was not split
612
    1	Root was split
613
*/
614
615
static int rtree_insert_level(MI_INFO *info, uint keynr, uchar *key, 
616
                             uint key_length, int ins_level)
617
{
618
  my_off_t old_root;
619
  MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
620
  int res;
621
  my_off_t new_page;
622
  DBUG_ENTER("rtree_insert_level");
623
624
  if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
625
  {
626
    if ((old_root = _mi_new(info, keyinfo, DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
627
      DBUG_RETURN(-1);
628
    info->buff_used = 1;
629
    mi_putint(info->buff, 2, 0);
630
    res = rtree_add_key(info, keyinfo, key, key_length, info->buff, NULL);
631
    if (_mi_write_keypage(info, keyinfo, old_root, DFLT_INIT_HITS, info->buff))
632
      DBUG_RETURN(1);
633
    info->s->state.key_root[keynr] = old_root;
634
    DBUG_RETURN(res);
635
  }
636
637
  switch ((res = rtree_insert_req(info, keyinfo, key, key_length, 
638
                                  old_root, &new_page, ins_level, 0)))
639
  {
640
    case 0: /* root was not split */
641
    {
642
      break;
643
    }
644
    case 1: /* root was split, grow a new root */
645
    { 
646
      uchar *new_root_buf;
647
      my_off_t new_root;
648
      uchar *new_key;
649
      uint nod_flag = info->s->base.key_reflength;
650
651
      DBUG_PRINT("rtree", ("root was split, grow a new root"));
652
      if (!(new_root_buf = (uchar*)my_alloca((uint)keyinfo->block_length + 
653
                                             MI_MAX_KEY_BUFF)))
654
      {
655
        my_errno = HA_ERR_OUT_OF_MEM;
656
        DBUG_RETURN(-1); /* purecov: inspected */
657
      }
658
659
      mi_putint(new_root_buf, 2, nod_flag);
660
      if ((new_root = _mi_new(info, keyinfo, DFLT_INIT_HITS)) ==
661
	  HA_OFFSET_ERROR)
662
        goto err1;
663
664
      new_key = new_root_buf + keyinfo->block_length + nod_flag;
665
666
      _mi_kpointer(info, new_key - nod_flag, old_root);
667
      if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, old_root))
668
        goto err1;
669
      if (rtree_add_key(info, keyinfo, new_key, key_length, new_root_buf, NULL) 
670
          == -1)
671
        goto err1;
672
      _mi_kpointer(info, new_key - nod_flag, new_page);
673
      if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, new_page))
674
        goto err1;
675
      if (rtree_add_key(info, keyinfo, new_key, key_length, new_root_buf, NULL) 
676
          == -1)
677
        goto err1;
678
      if (_mi_write_keypage(info, keyinfo, new_root,
679
                            DFLT_INIT_HITS, new_root_buf))
680
        goto err1;
681
      info->s->state.key_root[keynr] = new_root;
682
      DBUG_PRINT("rtree", ("new root page: %lu  level: %d  nod_flag: %u",
683
                           (ulong) new_root, 0, mi_test_if_nod(new_root_buf)));
684
685
      my_afree((uchar*)new_root_buf);
686
      break;
687
err1:
688
      my_afree((uchar*)new_root_buf);
689
      DBUG_RETURN(-1); /* purecov: inspected */
690
    }
691
    default:
692
    case -1: /* error */
693
    {
694
      break;
695
    }
696
  }
697
  DBUG_RETURN(res);
698
}
699
700
701
/*
702
  Insert key into the tree - interface function
703
704
  RETURN
705
    -1	Error
706
    0	OK
707
*/
708
709
int rtree_insert(MI_INFO *info, uint keynr, uchar *key, uint key_length)
710
{
711
  DBUG_ENTER("rtree_insert");
712
  DBUG_RETURN((!key_length ||
713
               (rtree_insert_level(info, keynr, key, key_length, -1) == -1)) ?
714
              -1 : 0);
715
}
716
717
718
/* 
719
  Fill reinsert page buffer 
720
721
  RETURN
722
    -1	Error
723
    0	OK
724
*/
725
726
static int rtree_fill_reinsert_list(stPageList *ReinsertList, my_off_t page, 
727
                                    int level)
728
{
729
  DBUG_ENTER("rtree_fill_reinsert_list");
730
  DBUG_PRINT("rtree", ("page: %lu  level: %d", (ulong) page, level));
731
  if (ReinsertList->n_pages == ReinsertList->m_pages)
732
  {
733
    ReinsertList->m_pages += REINSERT_BUFFER_INC;
734
    if (!(ReinsertList->pages = (stPageLevel*)my_realloc((uchar*)ReinsertList->pages, 
735
      ReinsertList->m_pages * sizeof(stPageLevel), MYF(MY_ALLOW_ZERO_PTR))))
736
      goto err1;
737
  }
738
  /* save page to ReinsertList */
739
  ReinsertList->pages[ReinsertList->n_pages].offs = page;
740
  ReinsertList->pages[ReinsertList->n_pages].level = level;
741
  ReinsertList->n_pages++;
742
  DBUG_RETURN(0);
743
744
err1:
745
  DBUG_RETURN(-1); /* purecov: inspected */
746
}
747
748
749
/*
750
  Go down and delete key from the tree
751
752
  RETURN
753
    -1	Error
754
    0	Deleted
755
    1	Not found
756
    2	Empty leaf
757
*/
758
759
static int rtree_delete_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, 
760
                           uint key_length, my_off_t page, uint *page_size, 
761
                           stPageList *ReinsertList, int level)
762
{
763
  uchar *k;
764
  uchar *last;
765
  ulong i;
766
  uint nod_flag;
767
  uchar *page_buf;
768
  int res;
769
  DBUG_ENTER("rtree_delete_req");
770
771
  if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
772
  {
773
    my_errno = HA_ERR_OUT_OF_MEM;
774
    DBUG_RETURN(-1); /* purecov: inspected */
775
  }
776
  if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0))
777
    goto err1;
778
  nod_flag = mi_test_if_nod(page_buf);
779
  DBUG_PRINT("rtree", ("page: %lu  level: %d  nod_flag: %u",
780
                       (ulong) page, level, nod_flag));
781
782
  k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
783
  last = rt_PAGE_END(page_buf);
784
785
  for (i = 0; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag), ++i)
786
  {
787
    if (nod_flag)
788
    { 
789
      /* not leaf */
790
      if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN))
791
      {
792
        switch ((res = rtree_delete_req(info, keyinfo, key, key_length, 
793
                  _mi_kpos(nod_flag, k), page_size, ReinsertList, level + 1)))
794
        {
795
          case 0: /* deleted */
796
          { 
797
            /* test page filling */
798
            if (*page_size + key_length >= rt_PAGE_MIN_SIZE(keyinfo->block_length)) 
799
            { 
800
              /* OK */
801
              /* Calculate a new key value (MBR) for the shrinked block. */
802
              if (rtree_set_key_mbr(info, keyinfo, k, key_length, 
803
                                  _mi_kpos(nod_flag, k)))
804
                goto err1;
805
              if (_mi_write_keypage(info, keyinfo, page,
806
                                    DFLT_INIT_HITS, page_buf))
807
                goto err1;
808
            }
809
            else
810
            { 
811
              /*
812
                Too small: delete key & add it descendant to reinsert list.
813
                Store position and level of the block so that it can be
814
                accessed later for inserting the remaining keys.
815
              */
816
              DBUG_PRINT("rtree", ("too small. move block to reinsert list"));
817
              if (rtree_fill_reinsert_list(ReinsertList, _mi_kpos(nod_flag, k),
818
                                           level + 1))
819
                goto err1;
820
              /*
821
                Delete the key that references the block. This makes the
822
                block disappear from the index. Hence we need to insert
823
                its remaining keys later. Note: if the block is a branch
824
                block, we do not only remove this block, but the whole
825
                subtree. So we need to re-insert its keys on the same
826
                level later to reintegrate the subtrees.
827
              */
828
              rtree_delete_key(info, page_buf, k, key_length, nod_flag);
829
              if (_mi_write_keypage(info, keyinfo, page,
830
                                    DFLT_INIT_HITS, page_buf))
831
                goto err1;
832
              *page_size = mi_getint(page_buf);
833
            }
834
            
835
            goto ok;
836
          }
837
          case 1: /* not found - continue searching */
838
          {
839
            break;
840
          }
841
          case 2: /* vacuous case: last key in the leaf */
842
          {
843
            rtree_delete_key(info, page_buf, k, key_length, nod_flag);
844
            if (_mi_write_keypage(info, keyinfo, page,
845
                                  DFLT_INIT_HITS, page_buf))
846
              goto err1;
847
            *page_size = mi_getint(page_buf);
848
            res = 0;
849
            goto ok;
850
          }
851
          default: /* error */
852
          case -1:
853
          {
854
            goto err1;
855
          }
856
        }
857
      }
858
    }
859
    else  
860
    {
861
      /* leaf */
862
      if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_EQUAL | MBR_DATA))
863
      {
864
        rtree_delete_key(info, page_buf, k, key_length, nod_flag);
865
        *page_size = mi_getint(page_buf);
866
        if (*page_size == 2) 
867
        {
868
          /* last key in the leaf */
869
          res = 2;
870
          if (_mi_dispose(info, keyinfo, page, DFLT_INIT_HITS))
871
            goto err1;
872
        }
873
        else
874
        {
875
          res = 0;
876
          if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
877
            goto err1;
878
        }
879
        goto ok;
880
      }
881
    }
882
  }
883
  res = 1;
884
885
ok:
886
  my_afree((uchar*)page_buf);
887
  DBUG_RETURN(res);
888
889
err1:
890
  my_afree((uchar*)page_buf);
891
  DBUG_RETURN(-1); /* purecov: inspected */
892
}
893
894
895
/*
896
  Delete key - interface function
897
898
  RETURN
899
    -1	Error
900
    0	Deleted
901
*/
902
903
int rtree_delete(MI_INFO *info, uint keynr, uchar *key, uint key_length)
904
{
905
  uint page_size;
906
  stPageList ReinsertList;
907
  my_off_t old_root;
908
  MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
909
  DBUG_ENTER("rtree_delete");
910
911
  if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
912
  {
913
    my_errno= HA_ERR_END_OF_FILE;
914
    DBUG_RETURN(-1); /* purecov: inspected */
915
  }
916
  DBUG_PRINT("rtree", ("starting deletion at root page: %lu",
917
                       (ulong) old_root));
918
919
  ReinsertList.pages = NULL;
920
  ReinsertList.n_pages = 0;
921
  ReinsertList.m_pages = 0;
922
  
923
  switch (rtree_delete_req(info, keyinfo, key, key_length, old_root, 
924
                                 &page_size, &ReinsertList, 0))
925
  {
926
    case 2: /* empty */
927
    {
928
      info->s->state.key_root[keynr] = HA_OFFSET_ERROR;
929
      DBUG_RETURN(0);
930
    }
931
    case 0: /* deleted */
932
    {
933
      uint nod_flag;
934
      ulong i;
935
      for (i = 0; i < ReinsertList.n_pages; ++i)
936
      {
937
        uchar *page_buf;
938
        uchar *k;
939
        uchar *last;
940
941
        if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
942
        {
943
          my_errno = HA_ERR_OUT_OF_MEM;
944
          goto err1;
945
        }
946
        if (!_mi_fetch_keypage(info, keyinfo, ReinsertList.pages[i].offs, 
947
                               DFLT_INIT_HITS, page_buf, 0))
948
          goto err1;
949
        nod_flag = mi_test_if_nod(page_buf);
950
        DBUG_PRINT("rtree", ("reinserting keys from "
951
                             "page: %lu  level: %d  nod_flag: %u",
952
                             (ulong) ReinsertList.pages[i].offs,
953
                             ReinsertList.pages[i].level, nod_flag));
954
955
        k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
956
        last = rt_PAGE_END(page_buf);
957
        for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag))
958
        {
959
          int res;
960
          if ((res= rtree_insert_level(info, keynr, k, key_length,
961
                                       ReinsertList.pages[i].level)) == -1)
962
          {
963
            my_afree((uchar*)page_buf);
964
            goto err1;
965
          }
966
          if (res)
967
          {
968
            ulong j;
969
            DBUG_PRINT("rtree", ("root has been split, adjust levels"));
970
            for (j= i; j < ReinsertList.n_pages; j++)
971
            {
972
              ReinsertList.pages[j].level++;
973
              DBUG_PRINT("rtree", ("keys from page: %lu  now level: %d",
974
                                   (ulong) ReinsertList.pages[i].offs,
975
                                   ReinsertList.pages[i].level));
976
            }
977
          }
978
        }
979
        my_afree((uchar*)page_buf);
980
        if (_mi_dispose(info, keyinfo, ReinsertList.pages[i].offs,
981
            DFLT_INIT_HITS))
982
          goto err1;
983
      }
984
      if (ReinsertList.pages)
985
        my_free((uchar*) ReinsertList.pages, MYF(0));
986
987
      /* check for redundant root (not leaf, 1 child) and eliminate */
988
      if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
989
        goto err1;
990
      if (!_mi_fetch_keypage(info, keyinfo, old_root, DFLT_INIT_HITS,
991
                             info->buff, 0))
992
        goto err1;
993
      nod_flag = mi_test_if_nod(info->buff);
994
      page_size = mi_getint(info->buff);
995
      if (nod_flag && (page_size == 2 + key_length + nod_flag))
996
      {
997
        my_off_t new_root = _mi_kpos(nod_flag,
998
                                     rt_PAGE_FIRST_KEY(info->buff, nod_flag));
999
        if (_mi_dispose(info, keyinfo, old_root, DFLT_INIT_HITS))
1000
          goto err1;
1001
        info->s->state.key_root[keynr] = new_root;
1002
      }
1003
      info->update= HA_STATE_DELETED;
1004
      DBUG_RETURN(0);
1005
1006
err1:
1007
      DBUG_RETURN(-1); /* purecov: inspected */
1008
    }
1009
    case 1: /* not found */
1010
    {
1011
      my_errno = HA_ERR_KEY_NOT_FOUND;
1012
      DBUG_RETURN(-1); /* purecov: inspected */
1013
    }
1014
    default:
1015
    case -1: /* error */
1016
    {
1017
      DBUG_RETURN(-1); /* purecov: inspected */
1018
    }
1019
  }
1020
}
1021
1022
1023
/* 
1024
  Estimate number of suitable keys in the tree 
1025
1026
  RETURN
1027
    estimated value
1028
*/
1029
1030
ha_rows rtree_estimate(MI_INFO *info, uint keynr, uchar *key, 
1031
                       uint key_length, uint flag)
1032
{
1033
  MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
1034
  my_off_t root;
1035
  uint i = 0;
1036
  uchar *k;
1037
  uchar *last;
1038
  uint nod_flag;
1039
  uchar *page_buf;
1040
  uint k_len;
1041
  double area = 0;
1042
  ha_rows res = 0;
1043
1044
  if (flag & MBR_DISJOINT)
1045
    return info->state->records;
1046
1047
  if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
1048
    return HA_POS_ERROR;
1049
  if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
1050
    return HA_POS_ERROR;
1051
  if (!_mi_fetch_keypage(info, keyinfo, root, DFLT_INIT_HITS, page_buf, 0))
1052
    goto err1;
1053
  nod_flag = mi_test_if_nod(page_buf);
1054
1055
  k_len = keyinfo->keylength - info->s->base.rec_reflength;
1056
1057
  k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
1058
  last = rt_PAGE_END(page_buf);
1059
1060
  for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag), ++i)
1061
  {
1062
    if (nod_flag)
1063
    {
1064
      double k_area = rtree_rect_volume(keyinfo->seg, k, key_length);
1065
1066
      /* The following should be safe, even if we compare doubles */
1067
      if (k_area == 0)
1068
      {
1069
        if (flag & (MBR_CONTAIN | MBR_INTERSECT))
1070
        {
1071
          area += 1;
1072
        }
1073
        else if (flag & (MBR_WITHIN | MBR_EQUAL))
1074
        {
1075
          if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN))
1076
            area += 1;
1077
        }
1078
        else
1079
          goto err1;
1080
      }
1081
      else
1082
      {
1083
        if (flag & (MBR_CONTAIN | MBR_INTERSECT))
1084
        {
1085
          area += rtree_overlapping_area(keyinfo->seg, key, k, key_length) / 
1086
                  k_area;
1087
        }
1088
        else if (flag & (MBR_WITHIN | MBR_EQUAL))
1089
        {
1090
          if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN))
1091
            area += rtree_rect_volume(keyinfo->seg, key, key_length) /
1092
                    k_area;
1093
        }
1094
        else
1095
          goto err1;
1096
      }
1097
    }
1098
    else
1099
    {
1100
      if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, flag))
1101
        ++res;
1102
    }
1103
  }
1104
  if (nod_flag)
1105
  {
1106
    if (i)
1107
      res = (ha_rows) (area / i * info->state->records);
1108
    else 
1109
      res = HA_POS_ERROR;
1110
  }
1111
1112
  my_afree((uchar*)page_buf);
1113
  return res;
1114
1115
err1:
1116
  my_afree((uchar*)page_buf);
1117
  return HA_POS_ERROR;
1118
}
1119
1120
#endif /*HAVE_RTREE_KEYS*/
1121