1 /*****************************************************************************
3 Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
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.
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.
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 St, Fifth Floor, Boston, MA 02110-1301 USA
17 *****************************************************************************/
19 /**************************************************//**
20 @file include/btr0pcur.ic
21 The index tree persistent cursor
23 Created 2/23/1996 Heikki Tuuri
24 *******************************************************/
27 /*********************************************************//**
28 Gets the rel_pos field for a cursor whose position has been stored.
29 @return BTR_PCUR_ON, ... */
34 const btr_pcur_t* cursor) /*!< in: persistent cursor */
37 ut_ad(cursor->old_rec);
38 ut_ad(cursor->old_stored == BTR_PCUR_OLD_STORED);
39 ut_ad(cursor->pos_state == BTR_PCUR_WAS_POSITIONED
40 || cursor->pos_state == BTR_PCUR_IS_POSITIONED);
42 return(cursor->rel_pos);
45 /*********************************************************//**
46 Sets the mtr field for a pcur. */
51 btr_pcur_t* cursor, /*!< in: persistent cursor */
52 mtr_t* mtr) /*!< in, own: mtr */
59 /*********************************************************//**
60 Gets the mtr field for a pcur.
66 btr_pcur_t* cursor) /*!< in: persistent cursor */
74 /*********************************************************//**
75 Returns the btr cursor component of a persistent cursor.
76 @return pointer to btr cursor component */
81 const btr_pcur_t* cursor) /*!< in: persistent cursor */
83 const btr_cur_t* btr_cur = &cursor->btr_cur;
84 return((btr_cur_t*) btr_cur);
87 /*********************************************************//**
88 Returns the page cursor component of a persistent cursor.
89 @return pointer to page cursor component */
92 btr_pcur_get_page_cur(
93 /*==================*/
94 const btr_pcur_t* cursor) /*!< in: persistent cursor */
96 return(btr_cur_get_page_cur(btr_pcur_get_btr_cur(cursor)));
98 #endif /* UNIV_DEBUG */
99 /*********************************************************//**
100 Returns the page of a persistent cursor.
101 @return pointer to the page */
106 btr_pcur_t* cursor) /*!< in: persistent cursor */
108 ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
110 return(btr_cur_get_page(btr_pcur_get_btr_cur(cursor)));
113 /*********************************************************//**
114 Returns the buffer block of a persistent cursor.
115 @return pointer to the block */
120 btr_pcur_t* cursor) /*!< in: persistent cursor */
122 ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
124 return(btr_cur_get_block(btr_pcur_get_btr_cur(cursor)));
127 /*********************************************************//**
128 Returns the record of a persistent cursor.
129 @return pointer to the record */
134 btr_pcur_t* cursor) /*!< in: persistent cursor */
136 ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
137 ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
139 return(btr_cur_get_rec(btr_pcur_get_btr_cur(cursor)));
142 /**************************************************************//**
143 Gets the up_match value for a pcur after a search.
144 @return number of matched fields at the cursor or to the right if
145 search mode was PAGE_CUR_GE, otherwise undefined */
148 btr_pcur_get_up_match(
149 /*==================*/
150 btr_pcur_t* cursor) /*!< in: memory buffer for persistent cursor */
152 btr_cur_t* btr_cursor;
154 ut_ad((cursor->pos_state == BTR_PCUR_WAS_POSITIONED)
155 || (cursor->pos_state == BTR_PCUR_IS_POSITIONED));
157 btr_cursor = btr_pcur_get_btr_cur(cursor);
159 ut_ad(btr_cursor->up_match != ULINT_UNDEFINED);
161 return(btr_cursor->up_match);
164 /**************************************************************//**
165 Gets the low_match value for a pcur after a search.
166 @return number of matched fields at the cursor or to the right if
167 search mode was PAGE_CUR_LE, otherwise undefined */
170 btr_pcur_get_low_match(
171 /*===================*/
172 btr_pcur_t* cursor) /*!< in: memory buffer for persistent cursor */
174 btr_cur_t* btr_cursor;
176 ut_ad((cursor->pos_state == BTR_PCUR_WAS_POSITIONED)
177 || (cursor->pos_state == BTR_PCUR_IS_POSITIONED));
179 btr_cursor = btr_pcur_get_btr_cur(cursor);
180 ut_ad(btr_cursor->low_match != ULINT_UNDEFINED);
182 return(btr_cursor->low_match);
185 /*********************************************************//**
186 Checks if the persistent cursor is after the last user record on
190 btr_pcur_is_after_last_on_page(
191 /*===========================*/
192 const btr_pcur_t* cursor) /*!< in: persistent cursor */
194 ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
195 ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
197 return(page_cur_is_after_last(btr_pcur_get_page_cur(cursor)));
200 /*********************************************************//**
201 Checks if the persistent cursor is before the first user record on
205 btr_pcur_is_before_first_on_page(
206 /*=============================*/
207 const btr_pcur_t* cursor) /*!< in: persistent cursor */
209 ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
210 ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
212 return(page_cur_is_before_first(btr_pcur_get_page_cur(cursor)));
215 /*********************************************************//**
216 Checks if the persistent cursor is on a user record. */
219 btr_pcur_is_on_user_rec(
220 /*====================*/
221 const btr_pcur_t* cursor) /*!< in: persistent cursor */
223 ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
224 ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
226 if (btr_pcur_is_before_first_on_page(cursor)
227 || btr_pcur_is_after_last_on_page(cursor)) {
235 /*********************************************************//**
236 Checks if the persistent cursor is before the first user record in
240 btr_pcur_is_before_first_in_tree(
241 /*=============================*/
242 btr_pcur_t* cursor, /*!< in: persistent cursor */
243 mtr_t* mtr) /*!< in: mtr */
245 ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
246 ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
248 if (btr_page_get_prev(btr_pcur_get_page(cursor), mtr) != FIL_NULL) {
253 return(page_cur_is_before_first(btr_pcur_get_page_cur(cursor)));
256 /*********************************************************//**
257 Checks if the persistent cursor is after the last user record in
261 btr_pcur_is_after_last_in_tree(
262 /*===========================*/
263 btr_pcur_t* cursor, /*!< in: persistent cursor */
264 mtr_t* mtr) /*!< in: mtr */
266 ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
267 ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
269 if (btr_page_get_next(btr_pcur_get_page(cursor), mtr) != FIL_NULL) {
274 return(page_cur_is_after_last(btr_pcur_get_page_cur(cursor)));
277 /*********************************************************//**
278 Moves the persistent cursor to the next record on the same page. */
281 btr_pcur_move_to_next_on_page(
282 /*==========================*/
283 btr_pcur_t* cursor) /*!< in/out: persistent cursor */
285 ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
286 ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
288 page_cur_move_to_next(btr_pcur_get_page_cur(cursor));
290 cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
293 /*********************************************************//**
294 Moves the persistent cursor to the previous record on the same page. */
297 btr_pcur_move_to_prev_on_page(
298 /*==========================*/
299 btr_pcur_t* cursor) /*!< in/out: persistent cursor */
301 ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
302 ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
304 page_cur_move_to_prev(btr_pcur_get_page_cur(cursor));
306 cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
309 /*********************************************************//**
310 Moves the persistent cursor to the last record on the same page. */
313 btr_pcur_move_to_last_on_page(
314 /*==========================*/
315 btr_pcur_t* cursor, /*!< in: persistent cursor */
316 mtr_t* mtr) /*!< in: mtr */
319 ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
321 page_cur_set_after_last(btr_pcur_get_block(cursor),
322 btr_pcur_get_page_cur(cursor));
324 cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
327 /*********************************************************//**
328 Moves the persistent cursor to the next user record in the tree. If no user
329 records are left, the cursor ends up 'after last in tree'.
330 @return TRUE if the cursor moved forward, ending on a user record */
333 btr_pcur_move_to_next_user_rec(
334 /*===========================*/
335 btr_pcur_t* cursor, /*!< in: persistent cursor; NOTE that the
336 function may release the page latch */
337 mtr_t* mtr) /*!< in: mtr */
339 ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
340 ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
341 cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
343 if (btr_pcur_is_after_last_on_page(cursor)) {
345 if (btr_pcur_is_after_last_in_tree(cursor, mtr)) {
350 btr_pcur_move_to_next_page(cursor, mtr);
352 btr_pcur_move_to_next_on_page(cursor);
355 if (btr_pcur_is_on_user_rec(cursor)) {
363 /*********************************************************//**
364 Moves the persistent cursor to the next record in the tree. If no records are
365 left, the cursor stays 'after last in tree'.
366 @return TRUE if the cursor was not after last in tree */
369 btr_pcur_move_to_next(
370 /*==================*/
371 btr_pcur_t* cursor, /*!< in: persistent cursor; NOTE that the
372 function may release the page latch */
373 mtr_t* mtr) /*!< in: mtr */
375 ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
376 ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
378 cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
380 if (btr_pcur_is_after_last_on_page(cursor)) {
382 if (btr_pcur_is_after_last_in_tree(cursor, mtr)) {
387 btr_pcur_move_to_next_page(cursor, mtr);
392 btr_pcur_move_to_next_on_page(cursor);
397 /**************************************************************//**
398 Commits the mtr and sets the pcur latch mode to BTR_NO_LATCHES,
399 that is, the cursor becomes detached.
400 Function btr_pcur_store_position should be used before calling this,
401 if restoration of cursor is wanted later. */
404 btr_pcur_commit_specify_mtr(
405 /*========================*/
406 btr_pcur_t* pcur, /*!< in: persistent cursor */
407 mtr_t* mtr) /*!< in: mtr to commit */
409 ut_a(pcur->pos_state == BTR_PCUR_IS_POSITIONED);
411 pcur->latch_mode = BTR_NO_LATCHES;
415 pcur->pos_state = BTR_PCUR_WAS_POSITIONED;
418 /**************************************************************//**
419 Sets the old_rec_buf field to NULL. */
424 btr_pcur_t* pcur) /*!< in: persistent cursor */
426 pcur->old_stored = BTR_PCUR_OLD_NOT_STORED;
427 pcur->old_rec_buf = NULL;
428 pcur->old_rec = NULL;
431 /**************************************************************//**
432 Initializes and opens a persistent cursor to an index tree. It should be
433 closed with btr_pcur_close. */
438 dict_index_t* index, /*!< in: index */
439 const dtuple_t* tuple, /*!< in: tuple on which search done */
440 ulint mode, /*!< in: PAGE_CUR_L, ...;
441 NOTE that if the search is made using a unique
442 prefix of a record, mode should be
443 PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
444 may end up on the previous page from the
446 ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
447 btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
448 const char* file, /*!< in: file name */
449 ulint line, /*!< in: line where called */
450 mtr_t* mtr) /*!< in: mtr */
452 btr_cur_t* btr_cursor;
454 /* Initialize the cursor */
456 btr_pcur_init(cursor);
458 cursor->latch_mode = latch_mode;
459 cursor->search_mode = mode;
461 /* Search with the tree cursor */
463 btr_cursor = btr_pcur_get_btr_cur(cursor);
465 btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
466 btr_cursor, 0, file, line, mtr);
467 cursor->pos_state = BTR_PCUR_IS_POSITIONED;
469 cursor->trx_if_known = NULL;
472 /**************************************************************//**
473 Opens an persistent cursor to an index tree without initializing the
477 btr_pcur_open_with_no_init_func(
478 /*============================*/
479 dict_index_t* index, /*!< in: index */
480 const dtuple_t* tuple, /*!< in: tuple on which search done */
481 ulint mode, /*!< in: PAGE_CUR_L, ...;
482 NOTE that if the search is made using a unique
483 prefix of a record, mode should be
484 PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
485 may end up on the previous page of the
487 ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ...;
488 NOTE that if has_search_latch != 0 then
489 we maybe do not acquire a latch on the cursor
490 page, but assume that the caller uses his
491 btr search latch to protect the record! */
492 btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
493 ulint has_search_latch,/*!< in: latch mode the caller
494 currently has on btr_search_latch:
496 const char* file, /*!< in: file name */
497 ulint line, /*!< in: line where called */
498 mtr_t* mtr) /*!< in: mtr */
500 btr_cur_t* btr_cursor;
502 cursor->latch_mode = latch_mode;
503 cursor->search_mode = mode;
505 /* Search with the tree cursor */
507 btr_cursor = btr_pcur_get_btr_cur(cursor);
509 btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
510 btr_cursor, has_search_latch,
512 cursor->pos_state = BTR_PCUR_IS_POSITIONED;
514 cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
516 cursor->trx_if_known = NULL;
519 /*****************************************************************//**
520 Opens a persistent cursor at either end of an index. */
523 btr_pcur_open_at_index_side(
524 /*========================*/
525 ibool from_left, /*!< in: TRUE if open to the low end,
526 FALSE if to the high end */
527 dict_index_t* index, /*!< in: index */
528 ulint latch_mode, /*!< in: latch mode */
529 btr_pcur_t* pcur, /*!< in: cursor */
530 ibool do_init, /*!< in: TRUE if should be initialized */
531 mtr_t* mtr) /*!< in: mtr */
533 pcur->latch_mode = latch_mode;
536 pcur->search_mode = PAGE_CUR_G;
538 pcur->search_mode = PAGE_CUR_L;
545 btr_cur_open_at_index_side(from_left, index, latch_mode,
546 btr_pcur_get_btr_cur(pcur), mtr);
547 pcur->pos_state = BTR_PCUR_IS_POSITIONED;
549 pcur->old_stored = BTR_PCUR_OLD_NOT_STORED;
551 pcur->trx_if_known = NULL;
554 /**********************************************************************//**
555 Positions a cursor at a randomly chosen position within a B-tree. */
558 btr_pcur_open_at_rnd_pos_func(
559 /*==========================*/
560 dict_index_t* index, /*!< in: index */
561 ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
562 btr_pcur_t* cursor, /*!< in/out: B-tree pcur */
563 const char* file, /*!< in: file name */
564 ulint line, /*!< in: line where called */
565 mtr_t* mtr) /*!< in: mtr */
567 /* Initialize the cursor */
569 cursor->latch_mode = latch_mode;
570 cursor->search_mode = PAGE_CUR_G;
572 btr_pcur_init(cursor);
574 btr_cur_open_at_rnd_pos_func(index, latch_mode,
575 btr_pcur_get_btr_cur(cursor),
577 cursor->pos_state = BTR_PCUR_IS_POSITIONED;
578 cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
580 cursor->trx_if_known = NULL;
583 /**************************************************************//**
584 Frees the possible memory heap of a persistent cursor and sets the latch
585 mode of the persistent cursor to BTR_NO_LATCHES. */
590 btr_pcur_t* cursor) /*!< in: persistent cursor */
592 if (cursor->old_rec_buf != NULL) {
594 mem_free(cursor->old_rec_buf);
596 cursor->old_rec = NULL;
597 cursor->old_rec_buf = NULL;
600 cursor->btr_cur.page_cur.rec = NULL;
601 cursor->btr_cur.page_cur.block = NULL;
602 cursor->old_rec = NULL;
603 cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
605 cursor->latch_mode = BTR_NO_LATCHES;
606 cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
608 cursor->trx_if_known = NULL;