1 /*****************************************************************************
2 
3 Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2018, 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/page0cur.h
22 The page cursor
23 
24 Created 10/4/1994 Heikki Tuuri
25 *************************************************************************/
26 
27 #ifndef page0cur_h
28 #define page0cur_h
29 
30 #include "buf0types.h"
31 #include "page0page.h"
32 #include "rem0types.h"
33 #include "rem0rec.h"
34 #include "data0data.h"
35 #include "mtr0mtr.h"
36 #include "gis0type.h"
37 
38 #ifdef UNIV_DEBUG
39 /*********************************************************//**
40 Gets pointer to the page frame where the cursor is positioned.
41 @return page */
42 UNIV_INLINE
43 page_t*
44 page_cur_get_page(
45 /*==============*/
46 	page_cur_t*	cur);	/*!< in: page cursor */
47 /*********************************************************//**
48 Gets pointer to the buffer block where the cursor is positioned.
49 @return page */
50 UNIV_INLINE
51 buf_block_t*
52 page_cur_get_block(
53 /*===============*/
54 	page_cur_t*	cur);	/*!< in: page cursor */
55 /*********************************************************//**
56 Gets pointer to the page frame where the cursor is positioned.
57 @return page */
58 UNIV_INLINE
59 page_zip_des_t*
60 page_cur_get_page_zip(
61 /*==================*/
62 	page_cur_t*	cur);	/*!< in: page cursor */
63 /*********************************************************//**
64 Gets the record where the cursor is positioned.
65 @return record */
66 UNIV_INLINE
67 rec_t*
68 page_cur_get_rec(
69 /*=============*/
70 	page_cur_t*	cur);	/*!< in: page cursor */
71 #else /* UNIV_DEBUG */
72 # define page_cur_get_page(cur)		page_align((cur)->rec)
73 # define page_cur_get_block(cur)	(cur)->block
74 # define page_cur_get_page_zip(cur)	buf_block_get_page_zip((cur)->block)
75 # define page_cur_get_rec(cur)		(cur)->rec
76 #endif /* UNIV_DEBUG */
77 /*********************************************************//**
78 Sets the cursor object to point before the first user record
79 on the page. */
80 UNIV_INLINE
81 void
82 page_cur_set_before_first(
83 /*======================*/
84 	const buf_block_t*	block,	/*!< in: index page */
85 	page_cur_t*		cur);	/*!< in: cursor */
86 /*********************************************************//**
87 Sets the cursor object to point after the last user record on
88 the page. */
89 UNIV_INLINE
90 void
91 page_cur_set_after_last(
92 /*====================*/
93 	const buf_block_t*	block,	/*!< in: index page */
94 	page_cur_t*		cur);	/*!< in: cursor */
95 /*********************************************************//**
96 Returns TRUE if the cursor is before first user record on page.
97 @return TRUE if at start */
98 UNIV_INLINE
99 ibool
100 page_cur_is_before_first(
101 /*=====================*/
102 	const page_cur_t*	cur);	/*!< in: cursor */
103 /*********************************************************//**
104 Returns TRUE if the cursor is after last user record.
105 @return TRUE if at end */
106 UNIV_INLINE
107 ibool
108 page_cur_is_after_last(
109 /*===================*/
110 	const page_cur_t*	cur);	/*!< in: cursor */
111 /**********************************************************//**
112 Positions the cursor on the given record. */
113 UNIV_INLINE
114 void
115 page_cur_position(
116 /*==============*/
117 	const rec_t*		rec,	/*!< in: record on a page */
118 	const buf_block_t*	block,	/*!< in: buffer block containing
119 					the record */
120 	page_cur_t*		cur);	/*!< out: page cursor */
121 /**********************************************************//**
122 Moves the cursor to the next record on page. */
123 UNIV_INLINE
124 void
125 page_cur_move_to_next(
126 /*==================*/
127 	page_cur_t*	cur);	/*!< in/out: cursor; must not be after last */
128 /**********************************************************//**
129 Moves the cursor to the previous record on page. */
130 UNIV_INLINE
131 void
132 page_cur_move_to_prev(
133 /*==================*/
134 	page_cur_t*	cur);	/*!< in/out: cursor; not before first */
135 
136 /***********************************************************//**
137 Inserts a record next to page cursor. Returns pointer to inserted record if
138 succeed, i.e., enough space available, NULL otherwise. The cursor stays at
139 the same logical position, but the physical position may change if it is
140 pointing to a compressed page that was reorganized.
141 
142 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
143 if this is a compressed leaf page in a secondary index.
144 This has to be done either within the same mini-transaction,
145 or by invoking ibuf_reset_free_bits() before mtr_commit().
146 
147 @return pointer to record if succeed, NULL otherwise */
148 UNIV_INLINE
149 rec_t*
150 page_cur_tuple_insert(
151 /*==================*/
152 	page_cur_t*	cursor,	/*!< in/out: a page cursor */
153 	const dtuple_t*	tuple,	/*!< in: pointer to a data tuple */
154 	dict_index_t*	index,	/*!< in: record descriptor */
155 	rec_offs**	offsets,/*!< out: offsets on *rec */
156 	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
157 	ulint		n_ext,	/*!< in: number of externally stored columns */
158 	mtr_t*		mtr)	/*!< in: mini-transaction handle, or NULL */
159 	MY_ATTRIBUTE((nonnull(1,2,3,4,5), warn_unused_result));
160 /***********************************************************//**
161 Inserts a record next to page cursor. Returns pointer to inserted record if
162 succeed, i.e., enough space available, NULL otherwise. The cursor stays at
163 the same logical position, but the physical position may change if it is
164 pointing to a compressed page that was reorganized.
165 
166 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
167 if this is a compressed leaf page in a secondary index.
168 This has to be done either within the same mini-transaction,
169 or by invoking ibuf_reset_free_bits() before mtr_commit().
170 
171 @return pointer to record if succeed, NULL otherwise */
172 UNIV_INLINE
173 rec_t*
174 page_cur_rec_insert(
175 /*================*/
176 	page_cur_t*	cursor,	/*!< in/out: a page cursor */
177 	const rec_t*	rec,	/*!< in: record to insert */
178 	dict_index_t*	index,	/*!< in: record descriptor */
179 	rec_offs*	offsets,/*!< in/out: rec_get_offsets(rec, index) */
180 	mtr_t*		mtr);	/*!< in: mini-transaction handle, or NULL */
181 /***********************************************************//**
182 Inserts a record next to page cursor on an uncompressed page.
183 Returns pointer to inserted record if succeed, i.e., enough
184 space available, NULL otherwise. The cursor stays at the same position.
185 @return pointer to record if succeed, NULL otherwise */
186 rec_t*
187 page_cur_insert_rec_low(
188 /*====================*/
189 	rec_t*		current_rec,/*!< in: pointer to current record after
190 				which the new record is inserted */
191 	dict_index_t*	index,	/*!< in: record descriptor */
192 	const rec_t*	rec,	/*!< in: pointer to a physical record */
193 	rec_offs*	offsets,/*!< in/out: rec_get_offsets(rec, index) */
194 	mtr_t*		mtr)	/*!< in: mini-transaction handle, or NULL */
195 	MY_ATTRIBUTE((nonnull(1,2,3,4), warn_unused_result));
196 
197 /***********************************************************//**
198 Inserts a record next to page cursor on a compressed and uncompressed
199 page. Returns pointer to inserted record if succeed, i.e.,
200 enough space available, NULL otherwise.
201 The cursor stays at the same position.
202 
203 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
204 if this is a compressed leaf page in a secondary index.
205 This has to be done either within the same mini-transaction,
206 or by invoking ibuf_reset_free_bits() before mtr_commit().
207 
208 @return pointer to record if succeed, NULL otherwise */
209 rec_t*
210 page_cur_insert_rec_zip(
211 /*====================*/
212 	page_cur_t*	cursor,	/*!< in/out: page cursor */
213 	dict_index_t*	index,	/*!< in: record descriptor */
214 	const rec_t*	rec,	/*!< in: pointer to a physical record */
215 	rec_offs*	offsets,/*!< in/out: rec_get_offsets(rec, index) */
216 	mtr_t*		mtr)	/*!< in: mini-transaction handle, or NULL */
217 	MY_ATTRIBUTE((nonnull(1,2,3,4), warn_unused_result));
218 /*************************************************************//**
219 Copies records from page to a newly created page, from a given record onward,
220 including that record. Infimum and supremum records are not copied.
221 
222 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
223 if this is a compressed leaf page in a secondary index.
224 This has to be done either within the same mini-transaction,
225 or by invoking ibuf_reset_free_bits() before mtr_commit(). */
226 void
227 page_copy_rec_list_end_to_created_page(
228 /*===================================*/
229 	page_t*		new_page,	/*!< in/out: index page to copy to */
230 	rec_t*		rec,		/*!< in: first record to copy */
231 	dict_index_t*	index,		/*!< in: record descriptor */
232 	mtr_t*		mtr);		/*!< in: mtr */
233 /***********************************************************//**
234 Deletes a record at the page cursor. The cursor is moved to the
235 next record after the deleted one. */
236 void
237 page_cur_delete_rec(
238 /*================*/
239 	page_cur_t*		cursor,	/*!< in/out: a page cursor */
240 	const dict_index_t*	index,	/*!< in: record descriptor */
241 	const rec_offs*		offsets,/*!< in: rec_get_offsets(
242 					cursor->rec, index) */
243 	mtr_t*			mtr);	/*!< in: mini-transaction handle */
244 
245 /** Search the right position for a page cursor.
246 @param[in] block buffer block
247 @param[in] index index tree
248 @param[in] tuple data tuple
249 @param[in] mode PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G, or PAGE_CUR_GE
250 @param[out] cursor page cursor
251 @return number of matched fields on the left */
252 UNIV_INLINE
253 ulint
254 page_cur_search(
255 	const buf_block_t*	block,
256 	const dict_index_t*	index,
257 	const dtuple_t*		tuple,
258 	page_cur_mode_t		mode,
259 	page_cur_t*		cursor);
260 
261 /** Search the right position for a page cursor.
262 @param[in] block buffer block
263 @param[in] index index tree
264 @param[in] tuple data tuple
265 @param[out] cursor page cursor
266 @return number of matched fields on the left */
267 UNIV_INLINE
268 ulint
269 page_cur_search(
270 	const buf_block_t*	block,
271 	const dict_index_t*	index,
272 	const dtuple_t*		tuple,
273 	page_cur_t*		cursor);
274 
275 /****************************************************************//**
276 Searches the right position for a page cursor. */
277 void
278 page_cur_search_with_match(
279 /*=======================*/
280 	const buf_block_t*	block,	/*!< in: buffer block */
281 	const dict_index_t*	index,	/*!< in: record descriptor */
282 	const dtuple_t*		tuple,	/*!< in: data tuple */
283 	page_cur_mode_t		mode,	/*!< in: PAGE_CUR_L,
284 					PAGE_CUR_LE, PAGE_CUR_G, or
285 					PAGE_CUR_GE */
286 	ulint*			iup_matched_fields,
287 					/*!< in/out: already matched
288 					fields in upper limit record */
289 	ulint*			ilow_matched_fields,
290 					/*!< in/out: already matched
291 					fields in lower limit record */
292 	page_cur_t*		cursor,	/*!< out: page cursor */
293 	rtr_info_t*		rtr_info);/*!< in/out: rtree search stack */
294 #ifdef BTR_CUR_HASH_ADAPT
295 /** Search the right position for a page cursor.
296 @param[in]	block			buffer block
297 @param[in]	index			index tree
298 @param[in]	tuple			key to be searched for
299 @param[in]	mode			search mode
300 @param[in,out]	iup_matched_fields	already matched fields in the
301 upper limit record
302 @param[in,out]	iup_matched_bytes	already matched bytes in the
303 first partially matched field in the upper limit record
304 @param[in,out]	ilow_matched_fields	already matched fields in the
305 lower limit record
306 @param[in,out]	ilow_matched_bytes	already matched bytes in the
307 first partially matched field in the lower limit record
308 @param[out]	cursor			page cursor */
309 void
310 page_cur_search_with_match_bytes(
311 	const buf_block_t*	block,
312 	const dict_index_t*	index,
313 	const dtuple_t*		tuple,
314 	page_cur_mode_t		mode,
315 	ulint*			iup_matched_fields,
316 	ulint*			iup_matched_bytes,
317 	ulint*			ilow_matched_fields,
318 	ulint*			ilow_matched_bytes,
319 	page_cur_t*		cursor);
320 #endif /* BTR_CUR_HASH_ADAPT */
321 /***********************************************************//**
322 Positions a page cursor on a randomly chosen user record on a page. If there
323 are no user records, sets the cursor on the infimum record. */
324 void
325 page_cur_open_on_rnd_user_rec(
326 /*==========================*/
327 	buf_block_t*	block,	/*!< in: page */
328 	page_cur_t*	cursor);/*!< out: page cursor */
329 /** Write a redo log record of inserting a record into an index page.
330 @param[in]	insert_rec	inserted record
331 @param[in]	rec_size	rec_get_size(insert_rec)
332 @param[in]	cursor_rec	predecessor of insert_rec
333 @param[in,out]	index		index tree
334 @param[in,out]	mtr		mini-transaction */
335 void
336 page_cur_insert_rec_write_log(
337 	const rec_t*	insert_rec,
338 	ulint		rec_size,
339 	const rec_t*	cursor_rec,
340 	dict_index_t*	index,
341 	mtr_t*		mtr)
342 	MY_ATTRIBUTE((nonnull));
343 /***********************************************************//**
344 Parses a log record of a record insert on a page.
345 @return end of log record or NULL */
346 byte*
347 page_cur_parse_insert_rec(
348 /*======================*/
349 	ibool		is_short,/*!< in: TRUE if short inserts */
350 	const byte*	ptr,	/*!< in: buffer */
351 	const byte*	end_ptr,/*!< in: buffer end */
352 	buf_block_t*	block,	/*!< in: page or NULL */
353 	dict_index_t*	index,	/*!< in: record descriptor */
354 	mtr_t*		mtr);	/*!< in: mtr or NULL */
355 /**********************************************************//**
356 Parses a log record of copying a record list end to a new created page.
357 @return end of log record or NULL */
358 byte*
359 page_parse_copy_rec_list_to_created_page(
360 /*=====================================*/
361 	byte*		ptr,	/*!< in: buffer */
362 	byte*		end_ptr,/*!< in: buffer end */
363 	buf_block_t*	block,	/*!< in: page or NULL */
364 	dict_index_t*	index,	/*!< in: record descriptor */
365 	mtr_t*		mtr);	/*!< in: mtr or NULL */
366 /***********************************************************//**
367 Parses log record of a record delete on a page.
368 @return pointer to record end or NULL */
369 byte*
370 page_cur_parse_delete_rec(
371 /*======================*/
372 	byte*		ptr,	/*!< in: buffer */
373 	byte*		end_ptr,/*!< in: buffer end */
374 	buf_block_t*	block,	/*!< in: page or NULL */
375 	dict_index_t*	index,	/*!< in: record descriptor */
376 	mtr_t*		mtr);	/*!< in: mtr or NULL */
377 /*******************************************************//**
378 Removes the record from a leaf page. This function does not log
379 any changes. It is used by the IMPORT tablespace functions.
380 @return true if success, i.e., the page did not become too empty */
381 bool
382 page_delete_rec(
383 /*============*/
384 	const dict_index_t*	index,	/*!< in: The index that the record
385 					belongs to */
386 	page_cur_t*		pcur,	/*!< in/out: page cursor on record
387 					to delete */
388 	page_zip_des_t*		page_zip,/*!< in: compressed page descriptor */
389 	const rec_offs*		offsets);/*!< in: offsets for record */
390 
391 /** Index page cursor */
392 
393 struct page_cur_t{
394 	const dict_index_t*	index;
395 	rec_t*		rec;	/*!< pointer to a record on page */
396 	rec_offs*	offsets;
397 	buf_block_t*	block;	/*!< pointer to the block containing rec */
398 };
399 
400 #include "page0cur.inl"
401 
402 #endif
403