~ubuntu-branches/ubuntu/trusty/mysql-5.6/trusty

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-02-12 11:54:27 UTC
  • Revision ID: package-import@ubuntu.com-20140212115427-oq6tfsqxl1wuwehi
Tags: upstream-5.6.15
ImportĀ upstreamĀ versionĀ 5.6.15

Show diffs side-by-side

added added

removed removed

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