641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
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)); |
|
641.2.1
by Monty Taylor
InnoDB Plugin 1.0.2 |
211 |
putc('\n', stderr); |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
212 |
if (cursor->trx_if_known) { |
213 |
trx_print(stderr, cursor->trx_if_known, 0); |
|
214 |
}
|
|
215 |
||
216 |
ut_error; |
|
217 |
}
|
|
218 |
||
219 |
if (UNIV_UNLIKELY |
|
220 |
(cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE |
|
221 |
|| cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE)) { |
|
222 |
||
223 |
/* In these cases we do not try an optimistic restoration,
|
|
224 |
but always do a search */
|
|
225 |
||
226 |
btr_cur_open_at_index_side( |
|
227 |
cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE, |
|
228 |
index, latch_mode, btr_pcur_get_btr_cur(cursor), mtr); |
|
229 |
||
230 |
cursor->block_when_stored = btr_pcur_get_block(cursor); |
|
231 |
||
232 |
return(FALSE); |
|
233 |
}
|
|
234 |
||
235 |
ut_a(cursor->old_rec); |
|
236 |
ut_a(cursor->old_n_fields); |
|
237 |
||
238 |
if (UNIV_LIKELY(latch_mode == BTR_SEARCH_LEAF) |
|
239 |
|| UNIV_LIKELY(latch_mode == BTR_MODIFY_LEAF)) { |
|
240 |
/* Try optimistic restoration */
|
|
241 |
||
242 |
if (UNIV_LIKELY(buf_page_optimistic_get( |
|
243 |
latch_mode, |
|
244 |
cursor->block_when_stored, |
|
245 |
cursor->modify_clock, mtr))) { |
|
246 |
cursor->pos_state = BTR_PCUR_IS_POSITIONED; |
|
641.2.1
by Monty Taylor
InnoDB Plugin 1.0.2 |
247 |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
248 |
buf_block_dbg_add_level(btr_pcur_get_block(cursor), |
249 |
SYNC_TREE_NODE); |
|
641.2.1
by Monty Taylor
InnoDB Plugin 1.0.2 |
250 |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
251 |
if (cursor->rel_pos == BTR_PCUR_ON) { |
252 |
#ifdef UNIV_DEBUG
|
|
253 |
const rec_t* rec; |
|
254 |
const ulint* offsets1; |
|
255 |
const ulint* offsets2; |
|
256 |
#endif /* UNIV_DEBUG */ |
|
257 |
cursor->latch_mode = latch_mode; |
|
258 |
#ifdef UNIV_DEBUG
|
|
259 |
rec = btr_pcur_get_rec(cursor); |
|
260 |
||
261 |
heap = mem_heap_create(256); |
|
262 |
offsets1 = rec_get_offsets( |
|
263 |
cursor->old_rec, index, NULL, |
|
264 |
cursor->old_n_fields, &heap); |
|
265 |
offsets2 = rec_get_offsets( |
|
266 |
rec, index, NULL, |
|
267 |
cursor->old_n_fields, &heap); |
|
268 |
||
269 |
ut_ad(!cmp_rec_rec(cursor->old_rec, |
|
270 |
rec, offsets1, offsets2, |
|
271 |
index)); |
|
272 |
mem_heap_free(heap); |
|
273 |
#endif /* UNIV_DEBUG */ |
|
274 |
return(TRUE); |
|
275 |
}
|
|
276 |
||
277 |
return(FALSE); |
|
278 |
}
|
|
279 |
}
|
|
280 |
||
281 |
/* If optimistic restoration did not succeed, open the cursor anew */
|
|
282 |
||
283 |
heap = mem_heap_create(256); |
|
284 |
||
285 |
tuple = dict_index_build_data_tuple(index, cursor->old_rec, |
|
286 |
cursor->old_n_fields, heap); |
|
287 |
||
288 |
/* Save the old search mode of the cursor */
|
|
289 |
old_mode = cursor->search_mode; |
|
290 |
||
291 |
if (UNIV_LIKELY(cursor->rel_pos == BTR_PCUR_ON)) { |
|
292 |
mode = PAGE_CUR_LE; |
|
293 |
} else if (cursor->rel_pos == BTR_PCUR_AFTER) { |
|
294 |
mode = PAGE_CUR_G; |
|
295 |
} else { |
|
296 |
ut_ad(cursor->rel_pos == BTR_PCUR_BEFORE); |
|
297 |
mode = PAGE_CUR_L; |
|
298 |
}
|
|
299 |
||
300 |
btr_pcur_open_with_no_init(index, tuple, mode, latch_mode, |
|
301 |
cursor, 0, mtr); |
|
302 |
||
303 |
/* Restore the old search mode */
|
|
304 |
cursor->search_mode = old_mode; |
|
305 |
||
306 |
if (cursor->rel_pos == BTR_PCUR_ON |
|
307 |
&& btr_pcur_is_on_user_rec(cursor) |
|
308 |
&& 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor), |
|
309 |
rec_get_offsets( |
|
310 |
btr_pcur_get_rec(cursor), index, |
|
311 |
NULL, ULINT_UNDEFINED, &heap))) { |
|
312 |
||
313 |
/* We have to store the NEW value for the modify clock, since
|
|
314 |
the cursor can now be on a different page! But we can retain
|
|
315 |
the value of old_rec */
|
|
316 |
||
317 |
cursor->block_when_stored = btr_pcur_get_block(cursor); |
|
318 |
cursor->modify_clock = buf_block_get_modify_clock( |
|
319 |
cursor->block_when_stored); |
|
320 |
cursor->old_stored = BTR_PCUR_OLD_STORED; |
|
321 |
||
322 |
mem_heap_free(heap); |
|
323 |
||
324 |
return(TRUE); |
|
325 |
}
|
|
326 |
||
327 |
mem_heap_free(heap); |
|
328 |
||
329 |
/* We have to store new position information, modify_clock etc.,
|
|
330 |
to the cursor because it can now be on a different page, the record
|
|
331 |
under it may have been removed, etc. */
|
|
332 |
||
333 |
btr_pcur_store_position(cursor, mtr); |
|
334 |
||
335 |
return(FALSE); |
|
336 |
}
|
|
337 |
||
338 |
/******************************************************************
|
|
339 |
If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY,
|
|
340 |
releases the page latch and bufferfix reserved by the cursor.
|
|
341 |
NOTE! In the case of BTR_LEAF_MODIFY, there should not exist changes
|
|
342 |
made by the current mini-transaction to the data protected by the
|
|
343 |
cursor latch, as then the latch must not be released until mtr_commit. */
|
|
344 |
UNIV_INTERN
|
|
345 |
void
|
|
346 |
btr_pcur_release_leaf( |
|
347 |
/*==================*/
|
|
348 |
btr_pcur_t* cursor, /* in: persistent cursor */ |
|
349 |
mtr_t* mtr) /* in: mtr */ |
|
350 |
{
|
|
351 |
buf_block_t* block; |
|
352 |
||
353 |
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED); |
|
354 |
ut_ad(cursor->latch_mode != BTR_NO_LATCHES); |
|
355 |
||
356 |
block = btr_pcur_get_block(cursor); |
|
357 |
||
358 |
btr_leaf_page_release(block, cursor->latch_mode, mtr); |
|
359 |
||
360 |
cursor->latch_mode = BTR_NO_LATCHES; |
|
361 |
||
362 |
cursor->pos_state = BTR_PCUR_WAS_POSITIONED; |
|
363 |
}
|
|
364 |
||
365 |
/*************************************************************
|
|
366 |
Moves the persistent cursor to the first record on the next page. Releases the
|
|
367 |
latch on the current page, and bufferunfixes it. Note that there must not be
|
|
368 |
modifications on the current page, as then the x-latch can be released only in
|
|
369 |
mtr_commit. */
|
|
370 |
UNIV_INTERN
|
|
371 |
void
|
|
372 |
btr_pcur_move_to_next_page( |
|
373 |
/*=======================*/
|
|
374 |
btr_pcur_t* cursor, /* in: persistent cursor; must be on the |
|
375 |
last record of the current page */
|
|
376 |
mtr_t* mtr) /* in: mtr */ |
|
377 |
{
|
|
378 |
ulint next_page_no; |
|
379 |
ulint space; |
|
380 |
ulint zip_size; |
|
381 |
page_t* page; |
|
382 |
buf_block_t* next_block; |
|
383 |
page_t* next_page; |
|
384 |
||
385 |
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED); |
|
386 |
ut_ad(cursor->latch_mode != BTR_NO_LATCHES); |
|
387 |
ut_ad(btr_pcur_is_after_last_on_page(cursor)); |
|
388 |
||
389 |
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; |
|
390 |
||
391 |
page = btr_pcur_get_page(cursor); |
|
392 |
next_page_no = btr_page_get_next(page, mtr); |
|
393 |
space = buf_block_get_space(btr_pcur_get_block(cursor)); |
|
394 |
zip_size = buf_block_get_zip_size(btr_pcur_get_block(cursor)); |
|
395 |
||
396 |
ut_ad(next_page_no != FIL_NULL); |
|
397 |
||
398 |
next_block = btr_block_get(space, zip_size, next_page_no, |
|
399 |
cursor->latch_mode, mtr); |
|
400 |
next_page = buf_block_get_frame(next_block); |
|
401 |
#ifdef UNIV_BTR_DEBUG
|
|
402 |
ut_a(page_is_comp(next_page) == page_is_comp(page)); |
|
403 |
ut_a(btr_page_get_prev(next_page, mtr) |
|
404 |
== buf_block_get_page_no(btr_pcur_get_block(cursor))); |
|
405 |
#endif /* UNIV_BTR_DEBUG */ |
|
406 |
next_block->check_index_page_at_flush = TRUE; |
|
407 |
||
408 |
btr_leaf_page_release(btr_pcur_get_block(cursor), |
|
409 |
cursor->latch_mode, mtr); |
|
410 |
||
411 |
page_cur_set_before_first(next_block, btr_pcur_get_page_cur(cursor)); |
|
412 |
||
413 |
page_check_dir(next_page); |
|
414 |
}
|
|
415 |
||
416 |
/*************************************************************
|
|
417 |
Moves the persistent cursor backward if it is on the first record of the page.
|
|
418 |
Commits mtr. Note that to prevent a possible deadlock, the operation
|
|
419 |
first stores the position of the cursor, commits mtr, acquires the necessary
|
|
420 |
latches and restores the cursor position again before returning. The
|
|
421 |
alphabetical position of the cursor is guaranteed to be sensible on
|
|
422 |
return, but it may happen that the cursor is not positioned on the last
|
|
423 |
record of any page, because the structure of the tree may have changed
|
|
424 |
during the time when the cursor had no latches. */
|
|
425 |
UNIV_INTERN
|
|
426 |
void
|
|
427 |
btr_pcur_move_backward_from_page( |
|
428 |
/*=============================*/
|
|
429 |
btr_pcur_t* cursor, /* in: persistent cursor, must be on the first |
|
430 |
record of the current page */
|
|
431 |
mtr_t* mtr) /* in: mtr */ |
|
432 |
{
|
|
433 |
ulint prev_page_no; |
|
434 |
ulint space; |
|
435 |
page_t* page; |
|
436 |
buf_block_t* prev_block; |
|
437 |
ulint latch_mode; |
|
438 |
ulint latch_mode2; |
|
439 |
||
440 |
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED); |
|
441 |
ut_ad(cursor->latch_mode != BTR_NO_LATCHES); |
|
442 |
ut_ad(btr_pcur_is_before_first_on_page(cursor)); |
|
443 |
ut_ad(!btr_pcur_is_before_first_in_tree(cursor, mtr)); |
|
444 |
||
445 |
latch_mode = cursor->latch_mode; |
|
446 |
||
447 |
if (latch_mode == BTR_SEARCH_LEAF) { |
|
448 |
||
449 |
latch_mode2 = BTR_SEARCH_PREV; |
|
450 |
||
451 |
} else if (latch_mode == BTR_MODIFY_LEAF) { |
|
452 |
||
453 |
latch_mode2 = BTR_MODIFY_PREV; |
|
454 |
} else { |
|
455 |
latch_mode2 = 0; /* To eliminate compiler warning */ |
|
456 |
ut_error; |
|
457 |
}
|
|
458 |
||
459 |
btr_pcur_store_position(cursor, mtr); |
|
460 |
||
461 |
mtr_commit(mtr); |
|
462 |
||
463 |
mtr_start(mtr); |
|
464 |
||
465 |
btr_pcur_restore_position(latch_mode2, cursor, mtr); |
|
466 |
||
467 |
page = btr_pcur_get_page(cursor); |
|
468 |
||
469 |
prev_page_no = btr_page_get_prev(page, mtr); |
|
470 |
space = buf_block_get_space(btr_pcur_get_block(cursor)); |
|
471 |
||
472 |
if (prev_page_no == FIL_NULL) { |
|
473 |
} else if (btr_pcur_is_before_first_on_page(cursor)) { |
|
474 |
||
475 |
prev_block = btr_pcur_get_btr_cur(cursor)->left_block; |
|
476 |
||
477 |
btr_leaf_page_release(btr_pcur_get_block(cursor), |
|
478 |
latch_mode, mtr); |
|
479 |
||
480 |
page_cur_set_after_last(prev_block, |
|
481 |
btr_pcur_get_page_cur(cursor)); |
|
482 |
} else { |
|
483 |
||
484 |
/* The repositioned cursor did not end on an infimum record on
|
|
485 |
a page. Cursor repositioning acquired a latch also on the
|
|
486 |
previous page, but we do not need the latch: release it. */
|
|
487 |
||
488 |
prev_block = btr_pcur_get_btr_cur(cursor)->left_block; |
|
489 |
||
490 |
btr_leaf_page_release(prev_block, latch_mode, mtr); |
|
491 |
}
|
|
492 |
||
493 |
cursor->latch_mode = latch_mode; |
|
494 |
||
495 |
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; |
|
496 |
}
|
|
497 |
||
498 |
/*************************************************************
|
|
499 |
Moves the persistent cursor to the previous record in the tree. If no records
|
|
500 |
are left, the cursor stays 'before first in tree'. */
|
|
501 |
UNIV_INTERN
|
|
502 |
ibool
|
|
503 |
btr_pcur_move_to_prev( |
|
504 |
/*==================*/
|
|
505 |
/* out: TRUE if the cursor was not before first
|
|
506 |
in tree */
|
|
507 |
btr_pcur_t* cursor, /* in: persistent cursor; NOTE that the |
|
508 |
function may release the page latch */
|
|
509 |
mtr_t* mtr) /* in: mtr */ |
|
510 |
{
|
|
511 |
ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); |
|
512 |
ut_ad(cursor->latch_mode != BTR_NO_LATCHES); |
|
513 |
||
514 |
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; |
|
515 |
||
516 |
if (btr_pcur_is_before_first_on_page(cursor)) { |
|
517 |
||
518 |
if (btr_pcur_is_before_first_in_tree(cursor, mtr)) { |
|
519 |
||
520 |
return(FALSE); |
|
521 |
}
|
|
522 |
||
523 |
btr_pcur_move_backward_from_page(cursor, mtr); |
|
524 |
||
525 |
return(TRUE); |
|
526 |
}
|
|
527 |
||
528 |
btr_pcur_move_to_prev_on_page(cursor); |
|
529 |
||
530 |
return(TRUE); |
|
531 |
}
|
|
532 |
||
533 |
/******************************************************************
|
|
534 |
If mode is PAGE_CUR_G or PAGE_CUR_GE, opens a persistent cursor on the first
|
|
535 |
user record satisfying the search condition, in the case PAGE_CUR_L or
|
|
536 |
PAGE_CUR_LE, on the last user record. If no such user record exists, then
|
|
537 |
in the first case sets the cursor after last in tree, and in the latter case
|
|
538 |
before first in tree. The latching mode must be BTR_SEARCH_LEAF or
|
|
539 |
BTR_MODIFY_LEAF. */
|
|
540 |
UNIV_INTERN
|
|
541 |
void
|
|
542 |
btr_pcur_open_on_user_rec( |
|
543 |
/*======================*/
|
|
544 |
dict_index_t* index, /* in: index */ |
|
545 |
const dtuple_t* tuple, /* in: tuple on which search done */ |
|
546 |
ulint mode, /* in: PAGE_CUR_L, ... */ |
|
547 |
ulint latch_mode, /* in: BTR_SEARCH_LEAF or |
|
548 |
BTR_MODIFY_LEAF */
|
|
549 |
btr_pcur_t* cursor, /* in: memory buffer for persistent |
|
550 |
cursor */
|
|
551 |
mtr_t* mtr) /* in: mtr */ |
|
552 |
{
|
|
553 |
btr_pcur_open(index, tuple, mode, latch_mode, cursor, mtr); |
|
554 |
||
555 |
if ((mode == PAGE_CUR_GE) || (mode == PAGE_CUR_G)) { |
|
556 |
||
557 |
if (btr_pcur_is_after_last_on_page(cursor)) { |
|
558 |
||
559 |
btr_pcur_move_to_next_user_rec(cursor, mtr); |
|
560 |
}
|
|
561 |
} else { |
|
562 |
ut_ad((mode == PAGE_CUR_LE) || (mode == PAGE_CUR_L)); |
|
563 |
||
564 |
/* Not implemented yet */
|
|
565 |
||
566 |
ut_error; |
|
567 |
}
|
|
568 |
}
|