~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/btr/btr0pcur.c

  • Committer: Monty Taylor
  • Date: 2008-11-16 06:29:53 UTC
  • mto: (584.1.9 devel)
  • mto: This revision was merged to the branch mainline in revision 589.
  • Revision ID: monty@inaugust.com-20081116062953-ivdltjmfe009b5fr
Moved stuff into item/

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
The index tree persistent cursor
 
3
 
 
4
(c) 1996 Innobase Oy
 
5
 
 
6
Created 2/23/1996 Heikki Tuuri
 
7
*******************************************************/
 
8
 
 
9
#include "btr0pcur.h"
 
10
 
 
11
#ifdef UNIV_NONINL
 
12
#include "btr0pcur.ic"
 
13
#endif
 
14
 
 
15
#include "ut0byte.h"
 
16
#include "rem0cmp.h"
 
17
#include "trx0trx.h"
 
18
 
 
19
/******************************************************************
 
20
Allocates memory for a persistent cursor object and initializes the cursor. */
 
21
UNIV_INTERN
 
22
btr_pcur_t*
 
23
btr_pcur_create_for_mysql(void)
 
24
/*============================*/
 
25
                                /* out, own: persistent cursor */
 
26
{
 
27
        btr_pcur_t*     pcur;
 
28
 
 
29
        pcur = mem_alloc(sizeof(btr_pcur_t));
 
30
 
 
31
        pcur->btr_cur.index = NULL;
 
32
        btr_pcur_init(pcur);
 
33
 
 
34
        return(pcur);
 
35
}
 
36
 
 
37
/******************************************************************
 
38
Frees the memory for a persistent cursor object. */
 
39
UNIV_INTERN
 
40
void
 
41
btr_pcur_free_for_mysql(
 
42
/*====================*/
 
43
        btr_pcur_t*     cursor) /* in, own: persistent cursor */
 
44
{
 
45
        if (cursor->old_rec_buf != NULL) {
 
46
 
 
47
                mem_free(cursor->old_rec_buf);
 
48
 
 
49
                cursor->old_rec_buf = NULL;
 
50
        }
 
51
 
 
52
        cursor->btr_cur.page_cur.rec = NULL;
 
53
        cursor->old_rec = NULL;
 
54
        cursor->old_n_fields = 0;
 
55
        cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
 
56
 
 
57
        cursor->latch_mode = BTR_NO_LATCHES;
 
58
        cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
 
59
 
 
60
        mem_free(cursor);
 
61
}
 
62
 
 
63
/******************************************************************
 
64
The position of the cursor is stored by taking an initial segment of the
 
65
record the cursor is positioned on, before, or after, and copying it to the
 
66
cursor data structure, or just setting a flag if the cursor id before the
 
67
first in an EMPTY tree, or after the last in an EMPTY tree. NOTE that the
 
68
page where the cursor is positioned must not be empty if the index tree is
 
69
not totally empty! */
 
70
UNIV_INTERN
 
71
void
 
72
btr_pcur_store_position(
 
73
/*====================*/
 
74
        btr_pcur_t*     cursor, /* in: persistent cursor */
 
75
        mtr_t*          mtr)    /* in: mtr */
 
76
{
 
77
        page_cur_t*     page_cursor;
 
78
        buf_block_t*    block;
 
79
        rec_t*          rec;
 
80
        dict_index_t*   index;
 
81
        page_t*         page;
 
82
        ulint           offs;
 
83
 
 
84
        ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
 
85
        ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
 
86
 
 
87
        block = btr_pcur_get_block(cursor);
 
88
        index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
 
89
 
 
90
        page_cursor = btr_pcur_get_page_cur(cursor);
 
91
 
 
92
        rec = page_cur_get_rec(page_cursor);
 
93
        page = page_align(rec);
 
94
        offs = page_offset(rec);
 
95
 
 
96
        ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_S_FIX)
 
97
              || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
 
98
        ut_a(cursor->latch_mode != BTR_NO_LATCHES);
 
99
 
 
100
        if (UNIV_UNLIKELY(page_get_n_recs(page) == 0)) {
 
101
                /* It must be an empty index tree; NOTE that in this case
 
102
                we do not store the modify_clock, but always do a search
 
103
                if we restore the cursor position */
 
104
 
 
105
                ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
 
106
                ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
 
107
 
 
108
                cursor->old_stored = BTR_PCUR_OLD_STORED;
 
109
 
 
110
                if (page_rec_is_supremum_low(offs)) {
 
111
 
 
112
                        cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
 
113
                } else {
 
114
                        cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE;
 
115
                }
 
116
 
 
117
                return;
 
118
        }
 
119
 
 
120
        if (page_rec_is_supremum_low(offs)) {
 
121
 
 
122
                rec = page_rec_get_prev(rec);
 
123
 
 
124
                cursor->rel_pos = BTR_PCUR_AFTER;
 
125
 
 
126
        } else if (page_rec_is_infimum_low(offs)) {
 
127
 
 
128
                rec = page_rec_get_next(rec);
 
129
 
 
130
                cursor->rel_pos = BTR_PCUR_BEFORE;
 
131
        } else {
 
132
                cursor->rel_pos = BTR_PCUR_ON;
 
133
        }
 
134
 
 
135
        cursor->old_stored = BTR_PCUR_OLD_STORED;
 
136
        cursor->old_rec = dict_index_copy_rec_order_prefix(
 
137
                index, rec, &cursor->old_n_fields,
 
138
                &cursor->old_rec_buf, &cursor->buf_size);
 
139
 
 
140
        cursor->block_when_stored = block;
 
141
        cursor->modify_clock = buf_block_get_modify_clock(block);
 
142
}
 
143
 
 
144
/******************************************************************
 
145
Copies the stored position of a pcur to another pcur. */
 
146
UNIV_INTERN
 
147
void
 
148
btr_pcur_copy_stored_position(
 
149
/*==========================*/
 
150
        btr_pcur_t*     pcur_receive,   /* in: pcur which will receive the
 
151
                                        position info */
 
152
        btr_pcur_t*     pcur_donate)    /* in: pcur from which the info is
 
153
                                        copied */
 
154
{
 
155
        if (pcur_receive->old_rec_buf) {
 
156
                mem_free(pcur_receive->old_rec_buf);
 
157
        }
 
158
 
 
159
        ut_memcpy(pcur_receive, pcur_donate, sizeof(btr_pcur_t));
 
160
 
 
161
        if (pcur_donate->old_rec_buf) {
 
162
 
 
163
                pcur_receive->old_rec_buf = mem_alloc(pcur_donate->buf_size);
 
164
 
 
165
                ut_memcpy(pcur_receive->old_rec_buf, pcur_donate->old_rec_buf,
 
166
                          pcur_donate->buf_size);
 
167
                pcur_receive->old_rec = pcur_receive->old_rec_buf
 
168
                        + (pcur_donate->old_rec - pcur_donate->old_rec_buf);
 
169
        }
 
170
 
 
171
        pcur_receive->old_n_fields = pcur_donate->old_n_fields;
 
172
}
 
173
 
 
174
/******************************************************************
 
175
Restores the stored position of a persistent cursor bufferfixing the page and
 
176
obtaining the specified latches. If the cursor position was saved when the
 
177
(1) cursor was positioned on a user record: this function restores the position
 
178
to the last record LESS OR EQUAL to the stored record;
 
179
(2) cursor was positioned on a page infimum record: restores the position to
 
180
the last record LESS than the user record which was the successor of the page
 
181
infimum;
 
182
(3) cursor was positioned on the page supremum: restores to the first record
 
183
GREATER than the user record which was the predecessor of the supremum.
 
184
(4) cursor was positioned before the first or after the last in an empty tree:
 
185
restores to before first or after the last in the tree. */
 
186
UNIV_INTERN
 
187
ibool
 
188
btr_pcur_restore_position(
 
189
/*======================*/
 
190
                                        /* out: TRUE if the cursor position
 
191
                                        was stored when it was on a user record
 
192
                                        and it can be restored on a user record
 
193
                                        whose ordering fields are identical to
 
194
                                        the ones of the original user record */
 
195
        ulint           latch_mode,     /* in: BTR_SEARCH_LEAF, ... */
 
196
        btr_pcur_t*     cursor,         /* in: detached persistent cursor */
 
197
        mtr_t*          mtr)            /* in: mtr */
 
198
{
 
199
        dict_index_t*   index;
 
200
        dtuple_t*       tuple;
 
201
        ulint           mode;
 
202
        ulint           old_mode;
 
203
        mem_heap_t*     heap;
 
204
 
 
205
        index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
 
206
 
 
207
        if (UNIV_UNLIKELY(cursor->old_stored != BTR_PCUR_OLD_STORED)
 
208
            || UNIV_UNLIKELY(cursor->pos_state != BTR_PCUR_WAS_POSITIONED
 
209
                             && cursor->pos_state != BTR_PCUR_IS_POSITIONED)) {
 
210
                ut_print_buf(stderr, cursor, sizeof(btr_pcur_t));
 
211
                if (cursor->trx_if_known) {
 
212
                        trx_print(stderr, cursor->trx_if_known, 0);
 
213
                }
 
214
 
 
215
                ut_error;
 
216
        }
 
217
 
 
218
        if (UNIV_UNLIKELY
 
219
            (cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
 
220
             || cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE)) {
 
221
 
 
222
                /* In these cases we do not try an optimistic restoration,
 
223
                but always do a search */
 
224
 
 
225
                btr_cur_open_at_index_side(
 
226
                        cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE,
 
227
                        index, latch_mode, btr_pcur_get_btr_cur(cursor), mtr);
 
228
 
 
229
                cursor->block_when_stored = btr_pcur_get_block(cursor);
 
230
 
 
231
                return(FALSE);
 
232
        }
 
233
 
 
234
        ut_a(cursor->old_rec);
 
235
        ut_a(cursor->old_n_fields);
 
236
 
 
237
        if (UNIV_LIKELY(latch_mode == BTR_SEARCH_LEAF)
 
238
            || UNIV_LIKELY(latch_mode == BTR_MODIFY_LEAF)) {
 
239
                /* Try optimistic restoration */
 
240
 
 
241
                if (UNIV_LIKELY(buf_page_optimistic_get(
 
242
                                        latch_mode,
 
243
                                        cursor->block_when_stored,
 
244
                                        cursor->modify_clock, mtr))) {
 
245
                        cursor->pos_state = BTR_PCUR_IS_POSITIONED;
 
246
#ifdef UNIV_SYNC_DEBUG
 
247
                        buf_block_dbg_add_level(btr_pcur_get_block(cursor),
 
248
                                                SYNC_TREE_NODE);
 
249
#endif /* UNIV_SYNC_DEBUG */
 
250
                        if (cursor->rel_pos == BTR_PCUR_ON) {
 
251
#ifdef UNIV_DEBUG
 
252
                                const rec_t*    rec;
 
253
                                const ulint*    offsets1;
 
254
                                const ulint*    offsets2;
 
255
#endif /* UNIV_DEBUG */
 
256
                                cursor->latch_mode = latch_mode;
 
257
#ifdef UNIV_DEBUG
 
258
                                rec = btr_pcur_get_rec(cursor);
 
259
 
 
260
                                heap = mem_heap_create(256);
 
261
                                offsets1 = rec_get_offsets(
 
262
                                        cursor->old_rec, index, NULL,
 
263
                                        cursor->old_n_fields, &heap);
 
264
                                offsets2 = rec_get_offsets(
 
265
                                        rec, index, NULL,
 
266
                                        cursor->old_n_fields, &heap);
 
267
 
 
268
                                ut_ad(!cmp_rec_rec(cursor->old_rec,
 
269
                                                   rec, offsets1, offsets2,
 
270
                                                   index));
 
271
                                mem_heap_free(heap);
 
272
#endif /* UNIV_DEBUG */
 
273
                                return(TRUE);
 
274
                        }
 
275
 
 
276
                        return(FALSE);
 
277
                }
 
278
        }
 
279
 
 
280
        /* If optimistic restoration did not succeed, open the cursor anew */
 
281
 
 
282
        heap = mem_heap_create(256);
 
283
 
 
284
        tuple = dict_index_build_data_tuple(index, cursor->old_rec,
 
285
                                            cursor->old_n_fields, heap);
 
286
 
 
287
        /* Save the old search mode of the cursor */
 
288
        old_mode = cursor->search_mode;
 
289
 
 
290
        if (UNIV_LIKELY(cursor->rel_pos == BTR_PCUR_ON)) {
 
291
                mode = PAGE_CUR_LE;
 
292
        } else if (cursor->rel_pos == BTR_PCUR_AFTER) {
 
293
                mode = PAGE_CUR_G;
 
294
        } else {
 
295
                ut_ad(cursor->rel_pos == BTR_PCUR_BEFORE);
 
296
                mode = PAGE_CUR_L;
 
297
        }
 
298
 
 
299
        btr_pcur_open_with_no_init(index, tuple, mode, latch_mode,
 
300
                                   cursor, 0, mtr);
 
301
 
 
302
        /* Restore the old search mode */
 
303
        cursor->search_mode = old_mode;
 
304
 
 
305
        if (cursor->rel_pos == BTR_PCUR_ON
 
306
            && btr_pcur_is_on_user_rec(cursor)
 
307
            && 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor),
 
308
                                   rec_get_offsets(
 
309
                                           btr_pcur_get_rec(cursor), index,
 
310
                                           NULL, ULINT_UNDEFINED, &heap))) {
 
311
 
 
312
                /* We have to store the NEW value for the modify clock, since
 
313
                the cursor can now be on a different page! But we can retain
 
314
                the value of old_rec */
 
315
 
 
316
                cursor->block_when_stored = btr_pcur_get_block(cursor);
 
317
                cursor->modify_clock = buf_block_get_modify_clock(
 
318
                        cursor->block_when_stored);
 
319
                cursor->old_stored = BTR_PCUR_OLD_STORED;
 
320
 
 
321
                mem_heap_free(heap);
 
322
 
 
323
                return(TRUE);
 
324
        }
 
325
 
 
326
        mem_heap_free(heap);
 
327
 
 
328
        /* We have to store new position information, modify_clock etc.,
 
329
        to the cursor because it can now be on a different page, the record
 
330
        under it may have been removed, etc. */
 
331
 
 
332
        btr_pcur_store_position(cursor, mtr);
 
333
 
 
334
        return(FALSE);
 
335
}
 
336
 
 
337
/******************************************************************
 
338
If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY,
 
339
releases the page latch and bufferfix reserved by the cursor.
 
340
NOTE! In the case of BTR_LEAF_MODIFY, there should not exist changes
 
341
made by the current mini-transaction to the data protected by the
 
342
cursor latch, as then the latch must not be released until mtr_commit. */
 
343
UNIV_INTERN
 
344
void
 
345
btr_pcur_release_leaf(
 
346
/*==================*/
 
347
        btr_pcur_t*     cursor, /* in: persistent cursor */
 
348
        mtr_t*          mtr)    /* in: mtr */
 
349
{
 
350
        buf_block_t*    block;
 
351
 
 
352
        ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
 
353
        ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
 
354
 
 
355
        block = btr_pcur_get_block(cursor);
 
356
 
 
357
        btr_leaf_page_release(block, cursor->latch_mode, mtr);
 
358
 
 
359
        cursor->latch_mode = BTR_NO_LATCHES;
 
360
 
 
361
        cursor->pos_state = BTR_PCUR_WAS_POSITIONED;
 
362
}
 
363
 
 
364
/*************************************************************
 
365
Moves the persistent cursor to the first record on the next page. Releases the
 
366
latch on the current page, and bufferunfixes it. Note that there must not be
 
367
modifications on the current page, as then the x-latch can be released only in
 
368
mtr_commit. */
 
369
UNIV_INTERN
 
370
void
 
371
btr_pcur_move_to_next_page(
 
372
/*=======================*/
 
373
        btr_pcur_t*     cursor, /* in: persistent cursor; must be on the
 
374
                                last record of the current page */
 
375
        mtr_t*          mtr)    /* in: mtr */
 
376
{
 
377
        ulint           next_page_no;
 
378
        ulint           space;
 
379
        ulint           zip_size;
 
380
        page_t*         page;
 
381
        buf_block_t*    next_block;
 
382
        page_t*         next_page;
 
383
 
 
384
        ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
 
385
        ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
 
386
        ut_ad(btr_pcur_is_after_last_on_page(cursor));
 
387
 
 
388
        cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
 
389
 
 
390
        page = btr_pcur_get_page(cursor);
 
391
        next_page_no = btr_page_get_next(page, mtr);
 
392
        space = buf_block_get_space(btr_pcur_get_block(cursor));
 
393
        zip_size = buf_block_get_zip_size(btr_pcur_get_block(cursor));
 
394
 
 
395
        ut_ad(next_page_no != FIL_NULL);
 
396
 
 
397
        next_block = btr_block_get(space, zip_size, next_page_no,
 
398
                                   cursor->latch_mode, mtr);
 
399
        next_page = buf_block_get_frame(next_block);
 
400
#ifdef UNIV_BTR_DEBUG
 
401
        ut_a(page_is_comp(next_page) == page_is_comp(page));
 
402
        ut_a(btr_page_get_prev(next_page, mtr)
 
403
             == buf_block_get_page_no(btr_pcur_get_block(cursor)));
 
404
#endif /* UNIV_BTR_DEBUG */
 
405
        next_block->check_index_page_at_flush = TRUE;
 
406
 
 
407
        btr_leaf_page_release(btr_pcur_get_block(cursor),
 
408
                              cursor->latch_mode, mtr);
 
409
 
 
410
        page_cur_set_before_first(next_block, btr_pcur_get_page_cur(cursor));
 
411
 
 
412
        page_check_dir(next_page);
 
413
}
 
414
 
 
415
/*************************************************************
 
416
Moves the persistent cursor backward if it is on the first record of the page.
 
417
Commits mtr. Note that to prevent a possible deadlock, the operation
 
418
first stores the position of the cursor, commits mtr, acquires the necessary
 
419
latches and restores the cursor position again before returning. The
 
420
alphabetical position of the cursor is guaranteed to be sensible on
 
421
return, but it may happen that the cursor is not positioned on the last
 
422
record of any page, because the structure of the tree may have changed
 
423
during the time when the cursor had no latches. */
 
424
UNIV_INTERN
 
425
void
 
426
btr_pcur_move_backward_from_page(
 
427
/*=============================*/
 
428
        btr_pcur_t*     cursor, /* in: persistent cursor, must be on the first
 
429
                                record of the current page */
 
430
        mtr_t*          mtr)    /* in: mtr */
 
431
{
 
432
        ulint           prev_page_no;
 
433
        ulint           space;
 
434
        page_t*         page;
 
435
        buf_block_t*    prev_block;
 
436
        ulint           latch_mode;
 
437
        ulint           latch_mode2;
 
438
 
 
439
        ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
 
440
        ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
 
441
        ut_ad(btr_pcur_is_before_first_on_page(cursor));
 
442
        ut_ad(!btr_pcur_is_before_first_in_tree(cursor, mtr));
 
443
 
 
444
        latch_mode = cursor->latch_mode;
 
445
 
 
446
        if (latch_mode == BTR_SEARCH_LEAF) {
 
447
 
 
448
                latch_mode2 = BTR_SEARCH_PREV;
 
449
 
 
450
        } else if (latch_mode == BTR_MODIFY_LEAF) {
 
451
 
 
452
                latch_mode2 = BTR_MODIFY_PREV;
 
453
        } else {
 
454
                latch_mode2 = 0; /* To eliminate compiler warning */
 
455
                ut_error;
 
456
        }
 
457
 
 
458
        btr_pcur_store_position(cursor, mtr);
 
459
 
 
460
        mtr_commit(mtr);
 
461
 
 
462
        mtr_start(mtr);
 
463
 
 
464
        btr_pcur_restore_position(latch_mode2, cursor, mtr);
 
465
 
 
466
        page = btr_pcur_get_page(cursor);
 
467
 
 
468
        prev_page_no = btr_page_get_prev(page, mtr);
 
469
        space = buf_block_get_space(btr_pcur_get_block(cursor));
 
470
 
 
471
        if (prev_page_no == FIL_NULL) {
 
472
        } else if (btr_pcur_is_before_first_on_page(cursor)) {
 
473
 
 
474
                prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
 
475
 
 
476
                btr_leaf_page_release(btr_pcur_get_block(cursor),
 
477
                                      latch_mode, mtr);
 
478
 
 
479
                page_cur_set_after_last(prev_block,
 
480
                                        btr_pcur_get_page_cur(cursor));
 
481
        } else {
 
482
 
 
483
                /* The repositioned cursor did not end on an infimum record on
 
484
                a page. Cursor repositioning acquired a latch also on the
 
485
                previous page, but we do not need the latch: release it. */
 
486
 
 
487
                prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
 
488
 
 
489
                btr_leaf_page_release(prev_block, latch_mode, mtr);
 
490
        }
 
491
 
 
492
        cursor->latch_mode = latch_mode;
 
493
 
 
494
        cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
 
495
}
 
496
 
 
497
/*************************************************************
 
498
Moves the persistent cursor to the previous record in the tree. If no records
 
499
are left, the cursor stays 'before first in tree'. */
 
500
UNIV_INTERN
 
501
ibool
 
502
btr_pcur_move_to_prev(
 
503
/*==================*/
 
504
                                /* out: TRUE if the cursor was not before first
 
505
                                in tree */
 
506
        btr_pcur_t*     cursor, /* in: persistent cursor; NOTE that the
 
507
                                function may release the page latch */
 
508
        mtr_t*          mtr)    /* in: mtr */
 
509
{
 
510
        ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
 
511
        ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
 
512
 
 
513
        cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
 
514
 
 
515
        if (btr_pcur_is_before_first_on_page(cursor)) {
 
516
 
 
517
                if (btr_pcur_is_before_first_in_tree(cursor, mtr)) {
 
518
 
 
519
                        return(FALSE);
 
520
                }
 
521
 
 
522
                btr_pcur_move_backward_from_page(cursor, mtr);
 
523
 
 
524
                return(TRUE);
 
525
        }
 
526
 
 
527
        btr_pcur_move_to_prev_on_page(cursor);
 
528
 
 
529
        return(TRUE);
 
530
}
 
531
 
 
532
/******************************************************************
 
533
If mode is PAGE_CUR_G or PAGE_CUR_GE, opens a persistent cursor on the first
 
534
user record satisfying the search condition, in the case PAGE_CUR_L or
 
535
PAGE_CUR_LE, on the last user record. If no such user record exists, then
 
536
in the first case sets the cursor after last in tree, and in the latter case
 
537
before first in tree. The latching mode must be BTR_SEARCH_LEAF or
 
538
BTR_MODIFY_LEAF. */
 
539
UNIV_INTERN
 
540
void
 
541
btr_pcur_open_on_user_rec(
 
542
/*======================*/
 
543
        dict_index_t*   index,          /* in: index */
 
544
        const dtuple_t* tuple,          /* in: tuple on which search done */
 
545
        ulint           mode,           /* in: PAGE_CUR_L, ... */
 
546
        ulint           latch_mode,     /* in: BTR_SEARCH_LEAF or
 
547
                                        BTR_MODIFY_LEAF */
 
548
        btr_pcur_t*     cursor,         /* in: memory buffer for persistent
 
549
                                        cursor */
 
550
        mtr_t*          mtr)            /* in: mtr */
 
551
{
 
552
        btr_pcur_open(index, tuple, mode, latch_mode, cursor, mtr);
 
553
 
 
554
        if ((mode == PAGE_CUR_GE) || (mode == PAGE_CUR_G)) {
 
555
 
 
556
                if (btr_pcur_is_after_last_on_page(cursor)) {
 
557
 
 
558
                        btr_pcur_move_to_next_user_rec(cursor, mtr);
 
559
                }
 
560
        } else {
 
561
                ut_ad((mode == PAGE_CUR_LE) || (mode == PAGE_CUR_L));
 
562
 
 
563
                /* Not implemented yet */
 
564
 
 
565
                ut_error;
 
566
        }
 
567
}