1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2017, 2021, MariaDB Corporation.
5 
6 This program is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free Software
8 Foundation; version 2 of the License.
9 
10 This program is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
17 
18 *****************************************************************************/
19 
20 /**************************************************//**
21 @file include/btr0pcur.h
22 The index tree persistent cursor
23 
24 Created 2/23/1996 Heikki Tuuri
25 *******************************************************/
26 
27 #ifndef btr0pcur_h
28 #define btr0pcur_h
29 
30 #include "dict0dict.h"
31 #include "btr0cur.h"
32 #include "buf0block_hint.h"
33 #include "btr0btr.h"
34 #include "gis0rtree.h"
35 
36 /* Relative positions for a stored cursor position */
37 enum btr_pcur_pos_t {
38 	BTR_PCUR_ON		= 1,
39 	BTR_PCUR_BEFORE		= 2,
40 	BTR_PCUR_AFTER		= 3,
41 /* Note that if the tree is not empty, btr_pcur_store_position does not
42 use the following, but only uses the above three alternatives, where the
43 position is stored relative to a specific record: this makes implementation
44 of a scroll cursor easier */
45 	BTR_PCUR_BEFORE_FIRST_IN_TREE	= 4,	/* in an empty tree */
46 	BTR_PCUR_AFTER_LAST_IN_TREE	= 5	/* in an empty tree */
47 };
48 
49 /**************************************************************//**
50 Allocates memory for a persistent cursor object and initializes the cursor.
51 @return own: persistent cursor */
52 btr_pcur_t*
53 btr_pcur_create_for_mysql(void);
54 /*============================*/
55 
56 /**************************************************************//**
57 Resets a persistent cursor object, freeing ::old_rec_buf if it is
58 allocated and resetting the other members to their initial values. */
59 void
60 btr_pcur_reset(
61 /*===========*/
62 	btr_pcur_t*	cursor);/*!< in, out: persistent cursor */
63 
64 /**************************************************************//**
65 Frees the memory for a persistent cursor object. */
66 void
67 btr_pcur_free_for_mysql(
68 /*====================*/
69 	btr_pcur_t*	cursor);	/*!< in, own: persistent cursor */
70 /**************************************************************//**
71 Copies the stored position of a pcur to another pcur. */
72 void
73 btr_pcur_copy_stored_position(
74 /*==========================*/
75 	btr_pcur_t*	pcur_receive,	/*!< in: pcur which will receive the
76 					position info */
77 	btr_pcur_t*	pcur_donate);	/*!< in: pcur from which the info is
78 					copied */
79 /**************************************************************//**
80 Sets the old_rec_buf field to NULL. */
81 UNIV_INLINE
82 void
83 btr_pcur_init(
84 /*==========*/
85 	btr_pcur_t*	pcur);	/*!< in: persistent cursor */
86 
87 /** Free old_rec_buf.
88 @param[in]	pcur	Persistent cursor holding old_rec to be freed. */
89 UNIV_INLINE
90 void
91 btr_pcur_free(
92 	btr_pcur_t*	pcur);
93 
94 /**************************************************************//**
95 Initializes and opens a persistent cursor to an index tree. It should be
96 closed with btr_pcur_close. */
97 UNIV_INLINE
98 dberr_t
99 btr_pcur_open_low(
100 /*==============*/
101 	dict_index_t*	index,	/*!< in: index */
102 	ulint		level,	/*!< in: level in the btree */
103 	const dtuple_t*	tuple,	/*!< in: tuple on which search done */
104 	page_cur_mode_t	mode,	/*!< in: PAGE_CUR_L, ...;
105 				NOTE that if the search is made using a unique
106 				prefix of a record, mode should be
107 				PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
108 				may end up on the previous page from the
109 				record! */
110 	ulint		latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
111 	btr_pcur_t*	cursor, /*!< in: memory buffer for persistent cursor */
112 	const char*	file,	/*!< in: file name */
113 	unsigned	line,	/*!< in: line where called */
114 	ib_uint64_t	autoinc,/*!< in: PAGE_ROOT_AUTO_INC to be written
115 				(0 if none) */
116 	mtr_t*		mtr);	/*!< in: mtr */
117 #define btr_pcur_open(i,t,md,l,c,m)				\
118 	btr_pcur_open_low(i,0,t,md,l,c,__FILE__,__LINE__,0,m)
119 /**************************************************************//**
120 Opens an persistent cursor to an index tree without initializing the
121 cursor. */
122 UNIV_INLINE
123 dberr_t
124 btr_pcur_open_with_no_init_func(
125 /*============================*/
126 	dict_index_t*	index,	/*!< in: index */
127 	const dtuple_t*	tuple,	/*!< in: tuple on which search done */
128 	page_cur_mode_t	mode,	/*!< in: PAGE_CUR_L, ...;
129 				NOTE that if the search is made using a unique
130 				prefix of a record, mode should be
131 				PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
132 				may end up on the previous page of the
133 				record! */
134 	ulint		latch_mode,/*!< in: BTR_SEARCH_LEAF, ...;
135 				NOTE that if ahi_latch then we might not
136 				acquire a cursor page latch, but assume
137 				that the ahi_latch protects the record! */
138 	btr_pcur_t*	cursor, /*!< in: memory buffer for persistent cursor */
139 #ifdef BTR_CUR_HASH_ADAPT
140 	rw_lock_t*	ahi_latch,
141 				/*!< in: adaptive hash index latch held
142 				by the caller, or NULL if none */
143 #endif /* BTR_CUR_HASH_ADAPT */
144 	const char*	file,	/*!< in: file name */
145 	unsigned	line,	/*!< in: line where called */
146 	mtr_t*		mtr);	/*!< in: mtr */
147 #ifdef BTR_CUR_HASH_ADAPT
148 # define btr_pcur_open_with_no_init(ix,t,md,l,cur,ahi,m)		\
149 	btr_pcur_open_with_no_init_func(ix,t,md,l,cur,ahi,__FILE__,__LINE__,m)
150 #else /* BTR_CUR_HASH_ADAPT */
151 # define btr_pcur_open_with_no_init(ix,t,md,l,cur,ahi,m)		\
152 	btr_pcur_open_with_no_init_func(ix,t,md,l,cur,__FILE__,__LINE__,m)
153 #endif /* BTR_CUR_HASH_ADAPT */
154 
155 /*****************************************************************//**
156 Opens a persistent cursor at either end of an index. */
157 UNIV_INLINE
158 dberr_t
159 btr_pcur_open_at_index_side(
160 /*========================*/
161 	bool		from_left,	/*!< in: true if open to the low end,
162 					false if to the high end */
163 	dict_index_t*	index,		/*!< in: index */
164 	ulint		latch_mode,	/*!< in: latch mode */
165 	btr_pcur_t*	pcur,		/*!< in/out: cursor */
166 	bool		init_pcur,	/*!< in: whether to initialize pcur */
167 	ulint		level,		/*!< in: level to search for
168 					(0=leaf) */
169 	mtr_t*		mtr)		/*!< in/out: mini-transaction */
170 	MY_ATTRIBUTE((nonnull));
171 /**************************************************************//**
172 Gets the up_match value for a pcur after a search.
173 @return number of matched fields at the cursor or to the right if
174 search mode was PAGE_CUR_GE, otherwise undefined */
175 UNIV_INLINE
176 ulint
177 btr_pcur_get_up_match(
178 /*==================*/
179 	const btr_pcur_t*	cursor); /*!< in: persistent cursor */
180 /**************************************************************//**
181 Gets the low_match value for a pcur after a search.
182 @return number of matched fields at the cursor or to the right if
183 search mode was PAGE_CUR_LE, otherwise undefined */
184 UNIV_INLINE
185 ulint
186 btr_pcur_get_low_match(
187 /*===================*/
188 	const btr_pcur_t*	cursor); /*!< in: persistent cursor */
189 /**************************************************************//**
190 If mode is PAGE_CUR_G or PAGE_CUR_GE, opens a persistent cursor on the first
191 user record satisfying the search condition, in the case PAGE_CUR_L or
192 PAGE_CUR_LE, on the last user record. If no such user record exists, then
193 in the first case sets the cursor after last in tree, and in the latter case
194 before first in tree. The latching mode must be BTR_SEARCH_LEAF or
195 BTR_MODIFY_LEAF. */
196 void
197 btr_pcur_open_on_user_rec_func(
198 /*===========================*/
199 	dict_index_t*	index,		/*!< in: index */
200 	const dtuple_t*	tuple,		/*!< in: tuple on which search done */
201 	page_cur_mode_t	mode,		/*!< in: PAGE_CUR_L, ... */
202 	ulint		latch_mode,	/*!< in: BTR_SEARCH_LEAF or
203 					BTR_MODIFY_LEAF */
204 	btr_pcur_t*	cursor,		/*!< in: memory buffer for persistent
205 					cursor */
206 	const char*	file,		/*!< in: file name */
207 	unsigned	line,		/*!< in: line where called */
208 	mtr_t*		mtr);		/*!< in: mtr */
209 #define btr_pcur_open_on_user_rec(i,t,md,l,c,m)				\
210 	btr_pcur_open_on_user_rec_func(i,t,md,l,c,__FILE__,__LINE__,m)
211 /**********************************************************************//**
212 Positions a cursor at a randomly chosen position within a B-tree.
213 @return true if the index is available and we have put the cursor, false
214 if the index is unavailable */
215 UNIV_INLINE
216 bool
217 btr_pcur_open_at_rnd_pos_func(
218 /*==========================*/
219 	dict_index_t*	index,		/*!< in: index */
220 	ulint		latch_mode,	/*!< in: BTR_SEARCH_LEAF, ... */
221 	btr_pcur_t*	cursor,		/*!< in/out: B-tree pcur */
222 	const char*	file,		/*!< in: file name */
223 	unsigned	line,		/*!< in: line where called */
224 	mtr_t*		mtr);		/*!< in: mtr */
225 #define btr_pcur_open_at_rnd_pos(i,l,c,m)				\
226 	btr_pcur_open_at_rnd_pos_func(i,l,c,__FILE__,__LINE__,m)
227 /**************************************************************//**
228 Frees the possible memory heap of a persistent cursor and sets the latch
229 mode of the persistent cursor to BTR_NO_LATCHES.
230 WARNING: this function does not release the latch on the page where the
231 cursor is currently positioned. The latch is acquired by the
232 "move to next/previous" family of functions. Since recursive shared locks
233 are not allowed, you must take care (if using the cursor in S-mode) to
234 manually release the latch by either calling
235 btr_leaf_page_release(btr_pcur_get_block(&pcur), pcur.latch_mode, mtr)
236 or by committing the mini-transaction right after btr_pcur_close().
237 A subsequent attempt to crawl the same page in the same mtr would cause
238 an assertion failure. */
239 UNIV_INLINE
240 void
241 btr_pcur_close(
242 /*===========*/
243 	btr_pcur_t*	cursor);	/*!< in: persistent cursor */
244 /**************************************************************//**
245 The position of the cursor is stored by taking an initial segment of the
246 record the cursor is positioned on, before, or after, and copying it to the
247 cursor data structure, or just setting a flag if the cursor id before the
248 first in an EMPTY tree, or after the last in an EMPTY tree. NOTE that the
249 page where the cursor is positioned must not be empty if the index tree is
250 not totally empty! */
251 void
252 btr_pcur_store_position(
253 /*====================*/
254 	btr_pcur_t*	cursor, /*!< in: persistent cursor */
255 	mtr_t*		mtr);	/*!< in: mtr */
256 /**************************************************************//**
257 Restores the stored position of a persistent cursor bufferfixing the page and
258 obtaining the specified latches. If the cursor position was saved when the
259 (1) cursor was positioned on a user record: this function restores the position
260 to the last record LESS OR EQUAL to the stored record;
261 (2) cursor was positioned on a page infimum record: restores the position to
262 the last record LESS than the user record which was the successor of the page
263 infimum;
264 (3) cursor was positioned on the page supremum: restores to the first record
265 GREATER than the user record which was the predecessor of the supremum.
266 (4) cursor was positioned before the first or after the last in an empty tree:
267 restores to before first or after the last in the tree.
268 @return TRUE if the cursor position was stored when it was on a user
269 record and it can be restored on a user record whose ordering fields
270 are identical to the ones of the original user record */
271 ibool
272 btr_pcur_restore_position_func(
273 /*===========================*/
274 	ulint		latch_mode,	/*!< in: BTR_SEARCH_LEAF, ... */
275 	btr_pcur_t*	cursor,		/*!< in: detached persistent cursor */
276 	const char*	file,		/*!< in: file name */
277 	unsigned	line,		/*!< in: line where called */
278 	mtr_t*		mtr);		/*!< in: mtr */
279 #define btr_pcur_restore_position(l,cur,mtr)				\
280 	btr_pcur_restore_position_func(l,cur,__FILE__,__LINE__,mtr)
281 /*********************************************************//**
282 Gets the rel_pos field for a cursor whose position has been stored.
283 @return BTR_PCUR_ON, ... */
284 UNIV_INLINE
285 ulint
286 btr_pcur_get_rel_pos(
287 /*=================*/
288 	const btr_pcur_t*	cursor);/*!< in: persistent cursor */
289 /**************************************************************//**
290 Commits the mtr and sets the pcur latch mode to BTR_NO_LATCHES,
291 that is, the cursor becomes detached.
292 Function btr_pcur_store_position should be used before calling this,
293 if restoration of cursor is wanted later. */
294 UNIV_INLINE
295 void
296 btr_pcur_commit_specify_mtr(
297 /*========================*/
298 	btr_pcur_t*	pcur,	/*!< in: persistent cursor */
299 	mtr_t*		mtr);	/*!< in: mtr to commit */
300 
301 /** Commits the mtr and sets the clustered index pcur and secondary index
302 pcur latch mode to BTR_NO_LATCHES, that is, the cursor becomes detached.
303 Function btr_pcur_store_position should be used for both cursor before
304 calling this, if restoration of cursor is wanted later.
305 @param[in]	pcur		persistent cursor
306 @param[in]	sec_pcur	secondary index persistent cursor
307 @param[in]	mtr		mtr to commit */
308 UNIV_INLINE
309 void
310 btr_pcurs_commit_specify_mtr(
311 	btr_pcur_t*	pcur,
312 	btr_pcur_t*	sec_pcur,
313 	mtr_t*		mtr);
314 
315 /*********************************************************//**
316 Moves the persistent cursor to the next record in the tree. If no records are
317 left, the cursor stays 'after last in tree'.
318 @return TRUE if the cursor was not after last in tree */
319 UNIV_INLINE
320 ibool
321 btr_pcur_move_to_next(
322 /*==================*/
323 	btr_pcur_t*	cursor,	/*!< in: persistent cursor; NOTE that the
324 				function may release the page latch */
325 	mtr_t*		mtr);	/*!< in: mtr */
326 /*********************************************************//**
327 Moves the persistent cursor to the previous record in the tree. If no records
328 are left, the cursor stays 'before first in tree'.
329 @return TRUE if the cursor was not before first in tree */
330 ibool
331 btr_pcur_move_to_prev(
332 /*==================*/
333 	btr_pcur_t*	cursor,	/*!< in: persistent cursor; NOTE that the
334 				function may release the page latch */
335 	mtr_t*		mtr);	/*!< in: mtr */
336 /*********************************************************//**
337 Moves the persistent cursor to the next user record in the tree. If no user
338 records are left, the cursor ends up 'after last in tree'.
339 @return TRUE if the cursor moved forward, ending on a user record */
340 UNIV_INLINE
341 ibool
342 btr_pcur_move_to_next_user_rec(
343 /*===========================*/
344 	btr_pcur_t*	cursor,	/*!< in: persistent cursor; NOTE that the
345 				function may release the page latch */
346 	mtr_t*		mtr);	/*!< in: mtr */
347 /*********************************************************//**
348 Moves the persistent cursor to the first record on the next page.
349 Releases the latch on the current page, and bufferunfixes it.
350 Note that there must not be modifications on the current page,
351 as then the x-latch can be released only in mtr_commit. */
352 void
353 btr_pcur_move_to_next_page(
354 /*=======================*/
355 	btr_pcur_t*	cursor,	/*!< in: persistent cursor; must be on the
356 				last record of the current page */
357 	mtr_t*		mtr);	/*!< in: mtr */
358 #ifdef UNIV_DEBUG
359 /*********************************************************//**
360 Returns the btr cursor component of a persistent cursor.
361 @return pointer to btr cursor component */
362 UNIV_INLINE
363 btr_cur_t*
364 btr_pcur_get_btr_cur(
365 /*=================*/
366 	const btr_pcur_t*	cursor);	/*!< in: persistent cursor */
367 /*********************************************************//**
368 Returns the page cursor component of a persistent cursor.
369 @return pointer to page cursor component */
370 UNIV_INLINE
371 page_cur_t*
372 btr_pcur_get_page_cur(
373 /*==================*/
374 	const btr_pcur_t*	cursor);	/*!< in: persistent cursor */
375 /*********************************************************//**
376 Returns the page of a persistent cursor.
377 @return pointer to the page */
378 UNIV_INLINE
379 page_t*
380 btr_pcur_get_page(
381 /*==============*/
382 	const btr_pcur_t*	cursor);/*!< in: persistent cursor */
383 /*********************************************************//**
384 Returns the buffer block of a persistent cursor.
385 @return pointer to the block */
386 UNIV_INLINE
387 buf_block_t*
388 btr_pcur_get_block(
389 /*===============*/
390 	const btr_pcur_t*	cursor);/*!< in: persistent cursor */
391 /*********************************************************//**
392 Returns the record of a persistent cursor.
393 @return pointer to the record */
394 UNIV_INLINE
395 rec_t*
396 btr_pcur_get_rec(
397 /*=============*/
398 	const btr_pcur_t*	cursor);/*!< in: persistent cursor */
399 #else /* UNIV_DEBUG */
400 # define btr_pcur_get_btr_cur(cursor) (&(cursor)->btr_cur)
401 # define btr_pcur_get_page_cur(cursor) (&(cursor)->btr_cur.page_cur)
402 # define btr_pcur_get_page(cursor) ((cursor)->btr_cur.page_cur.block->frame)
403 # define btr_pcur_get_block(cursor) ((cursor)->btr_cur.page_cur.block)
404 # define btr_pcur_get_rec(cursor) ((cursor)->btr_cur.page_cur.rec)
405 #endif /* UNIV_DEBUG */
406 /*********************************************************//**
407 Checks if the persistent cursor is on a user record. */
408 UNIV_INLINE
409 ibool
410 btr_pcur_is_on_user_rec(
411 /*====================*/
412 	const btr_pcur_t*	cursor);/*!< in: persistent cursor */
413 /*********************************************************//**
414 Checks if the persistent cursor is after the last user record on
415 a page. */
416 UNIV_INLINE
417 ibool
418 btr_pcur_is_after_last_on_page(
419 /*===========================*/
420 	const btr_pcur_t*	cursor);/*!< in: persistent cursor */
421 /*********************************************************//**
422 Checks if the persistent cursor is before the first user record on
423 a page. */
424 UNIV_INLINE
425 ibool
426 btr_pcur_is_before_first_on_page(
427 /*=============================*/
428 	const btr_pcur_t*	cursor);/*!< in: persistent cursor */
429 /*********************************************************//**
430 Checks if the persistent cursor is before the first user record in
431 the index tree. */
432 static inline bool btr_pcur_is_before_first_in_tree(btr_pcur_t* cursor);
433 /*********************************************************//**
434 Checks if the persistent cursor is after the last user record in
435 the index tree. */
436 static inline bool btr_pcur_is_after_last_in_tree(btr_pcur_t* cursor);
437 /*********************************************************//**
438 Moves the persistent cursor to the next record on the same page. */
439 UNIV_INLINE
440 void
441 btr_pcur_move_to_next_on_page(
442 /*==========================*/
443 	btr_pcur_t*	cursor);/*!< in/out: persistent cursor */
444 /*********************************************************//**
445 Moves the persistent cursor to the previous record on the same page. */
446 UNIV_INLINE
447 void
448 btr_pcur_move_to_prev_on_page(
449 /*==========================*/
450 	btr_pcur_t*	cursor);/*!< in/out: persistent cursor */
451 /*********************************************************//**
452 Moves the persistent cursor to the infimum record on the same page. */
453 UNIV_INLINE
454 void
455 btr_pcur_move_before_first_on_page(
456 /*===============================*/
457 	btr_pcur_t*	cursor); /*!< in/out: persistent cursor */
458 
459 /** Position state of persistent B-tree cursor. */
460 enum pcur_pos_t {
461 	/** The persistent cursor is not positioned. */
462 	BTR_PCUR_NOT_POSITIONED = 0,
463 	/** The persistent cursor was previously positioned.
464 	TODO: currently, the state can be BTR_PCUR_IS_POSITIONED,
465 	though it really should be BTR_PCUR_WAS_POSITIONED,
466 	because we have no obligation to commit the cursor with
467 	mtr; similarly latch_mode may be out of date. This can
468 	lead to problems if btr_pcur is not used the right way;
469 	all current code should be ok. */
470 	BTR_PCUR_WAS_POSITIONED,
471 	/** The persistent cursor is positioned by optimistic get to the same
472 	record as it was positioned at. Not used for rel_pos == BTR_PCUR_ON.
473 	It may need adjustment depending on previous/current search direction
474 	and rel_pos. */
475 	BTR_PCUR_IS_POSITIONED_OPTIMISTIC,
476 	/** The persistent cursor is positioned by index search.
477 	Or optimistic get for rel_pos == BTR_PCUR_ON. */
478 	BTR_PCUR_IS_POSITIONED
479 };
480 
481 /* The persistent B-tree cursor structure. This is used mainly for SQL
482 selects, updates, and deletes. */
483 
484 struct btr_pcur_t{
485 	/** a B-tree cursor */
486 	btr_cur_t	btr_cur;
487 	/** see TODO note below!
488 	BTR_SEARCH_LEAF, BTR_MODIFY_LEAF, BTR_MODIFY_TREE or BTR_NO_LATCHES,
489 	depending on the latching state of the page and tree where the cursor
490 	is positioned; BTR_NO_LATCHES means that the cursor is not currently
491 	positioned:
492 	we say then that the cursor is detached; it can be restored to
493 	attached if the old position was stored in old_rec */
494 	ulint		latch_mode;
495 	/** true if old_rec is stored */
496 	bool		old_stored;
497 	/** if cursor position is stored, contains an initial segment of the
498 	latest record cursor was positioned either on, before or after */
499 	rec_t*		old_rec;
500 	/** btr_cur.index->n_core_fields when old_rec was copied */
501 	uint16		old_n_core_fields;
502 	/** number of fields in old_rec */
503 	uint16		old_n_fields;
504 	/** BTR_PCUR_ON, BTR_PCUR_BEFORE, or BTR_PCUR_AFTER, depending on
505 	whether cursor was on, before, or after the old_rec record */
506 	enum btr_pcur_pos_t	rel_pos;
507 	/** buffer block when the position was stored */
508 	buf::Block_hint		block_when_stored;
509 	/** the modify clock value of the buffer block when the cursor position
510 	was stored */
511 	ib_uint64_t	modify_clock;
512 	/** btr_pcur_store_position() and btr_pcur_restore_position() state. */
513 	enum pcur_pos_t	pos_state;
514 	/** PAGE_CUR_G, ... */
515 	page_cur_mode_t	search_mode;
516 	/** the transaction, if we know it; otherwise this field is not defined;
517 	can ONLY BE USED in error prints in fatal assertion failures! */
518 	trx_t*		trx_if_known;
519 	/*-----------------------------*/
520 	/* NOTE that the following fields may possess dynamically allocated
521 	memory which should be freed if not needed anymore! */
522 
523 	/** NULL, or a dynamically allocated buffer for old_rec */
524 	byte*		old_rec_buf;
525 	/** old_rec_buf size if old_rec_buf is not NULL */
526 	ulint		buf_size;
527 
btr_pcur_tbtr_pcur_t528 	btr_pcur_t() :
529 		btr_cur(), latch_mode(0), old_stored(false), old_rec(NULL),
530 		old_n_fields(0), rel_pos(btr_pcur_pos_t(0)),
531 		block_when_stored(),
532 		modify_clock(0), pos_state(BTR_PCUR_NOT_POSITIONED),
533 		search_mode(PAGE_CUR_UNSUPP), trx_if_known(NULL),
534 		old_rec_buf(NULL), buf_size(0)
535 	{
536 		btr_cur.init();
537 	}
538 
539 	/** Return the index of this persistent cursor */
indexbtr_pcur_t540 	dict_index_t*	index() const { return(btr_cur.index); }
541 };
542 
543 #include "btr0pcur.inl"
544 
545 #endif
546