~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Merge Revision revid:marko.makela@oracle.com-20100505101406-u4low2x26q6itck0 from MySQL InnoDB

Original revid:marko.makela@oracle.com-20100505101406-u4low2x26q6itck0

Original Authors: Marko Mäkelä <marko.makela@oracle.com>
Original commit message:
Merge from mysql-5.1-innodb:

  ------------------------------------------------------------
  revno: 3446
  revision-id: marko.makela@oracle.com-20100505100507-6kcd2hf32hruxbv7
  parent: marko.makela@oracle.com-20100505095328-vetnl0flhmhao7p5
  committer: Marko Mäkelä <marko.makela@oracle.com>
  branch nick: 5.1-innodb
  timestamp: Wed 2010-05-05 13:05:07 +0300
  message:
    Add Valgrind diagnostics to track down Bug #38999.
  ------------------------------------------------------------

Show diffs side-by-side

added added

removed removed

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