1 /*****************************************************************************
2 
3 Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8 
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation.  The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 GNU General Public License, version 2.0, for more details.
20 
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24 
25 *****************************************************************************/
26 
27 /********************************************************************//**
28 @file include/page0cur.h
29 The page cursor
30 
31 Created 10/4/1994 Heikki Tuuri
32 *************************************************************************/
33 
34 #ifndef page0cur_h
35 #define page0cur_h
36 
37 #include "univ.i"
38 
39 #include "buf0types.h"
40 #include "page0page.h"
41 #include "rem0rec.h"
42 #include "data0data.h"
43 #include "mtr0mtr.h"
44 
45 
46 #define PAGE_CUR_ADAPT
47 
48 /* Page cursor search modes; the values must be in this order! */
49 
50 #define	PAGE_CUR_UNSUPP	0
51 #define	PAGE_CUR_G	1
52 #define	PAGE_CUR_GE	2
53 #define	PAGE_CUR_L	3
54 #define	PAGE_CUR_LE	4
55 /*#define PAGE_CUR_LE_OR_EXTENDS 5*/ /* This is a search mode used in
56 				 "column LIKE 'abc%' ORDER BY column DESC";
57 				 we have to find strings which are <= 'abc' or
58 				 which extend it */
59 #ifdef UNIV_SEARCH_DEBUG
60 # define PAGE_CUR_DBG	6	/* As PAGE_CUR_LE, but skips search shortcut */
61 #endif /* UNIV_SEARCH_DEBUG */
62 
63 #ifdef UNIV_DEBUG
64 /*********************************************************//**
65 Gets pointer to the page frame where the cursor is positioned.
66 @return	page */
67 UNIV_INLINE
68 page_t*
69 page_cur_get_page(
70 /*==============*/
71 	page_cur_t*	cur);	/*!< in: page cursor */
72 /*********************************************************//**
73 Gets pointer to the buffer block where the cursor is positioned.
74 @return	page */
75 UNIV_INLINE
76 buf_block_t*
77 page_cur_get_block(
78 /*===============*/
79 	page_cur_t*	cur);	/*!< in: page cursor */
80 /*********************************************************//**
81 Gets pointer to the page frame where the cursor is positioned.
82 @return	page */
83 UNIV_INLINE
84 page_zip_des_t*
85 page_cur_get_page_zip(
86 /*==================*/
87 	page_cur_t*	cur);	/*!< in: page cursor */
88 /*********************************************************//**
89 Gets the record where the cursor is positioned.
90 @return	record */
91 UNIV_INLINE
92 rec_t*
93 page_cur_get_rec(
94 /*=============*/
95 	page_cur_t*	cur);	/*!< in: page cursor */
96 #else /* UNIV_DEBUG */
97 # define page_cur_get_page(cur)		page_align((cur)->rec)
98 # define page_cur_get_block(cur)	(cur)->block
99 # define page_cur_get_page_zip(cur)	buf_block_get_page_zip((cur)->block)
100 # define page_cur_get_rec(cur)		(cur)->rec
101 #endif /* UNIV_DEBUG */
102 /*********************************************************//**
103 Sets the cursor object to point before the first user record
104 on the page. */
105 UNIV_INLINE
106 void
107 page_cur_set_before_first(
108 /*======================*/
109 	const buf_block_t*	block,	/*!< in: index page */
110 	page_cur_t*		cur);	/*!< in: cursor */
111 /*********************************************************//**
112 Sets the cursor object to point after the last user record on
113 the page. */
114 UNIV_INLINE
115 void
116 page_cur_set_after_last(
117 /*====================*/
118 	const buf_block_t*	block,	/*!< in: index page */
119 	page_cur_t*		cur);	/*!< in: cursor */
120 /*********************************************************//**
121 Returns TRUE if the cursor is before first user record on page.
122 @return	TRUE if at start */
123 UNIV_INLINE
124 ibool
125 page_cur_is_before_first(
126 /*=====================*/
127 	const page_cur_t*	cur);	/*!< in: cursor */
128 /*********************************************************//**
129 Returns TRUE if the cursor is after last user record.
130 @return	TRUE if at end */
131 UNIV_INLINE
132 ibool
133 page_cur_is_after_last(
134 /*===================*/
135 	const page_cur_t*	cur);	/*!< in: cursor */
136 /**********************************************************//**
137 Positions the cursor on the given record. */
138 UNIV_INLINE
139 void
140 page_cur_position(
141 /*==============*/
142 	const rec_t*		rec,	/*!< in: record on a page */
143 	const buf_block_t*	block,	/*!< in: buffer block containing
144 					the record */
145 	page_cur_t*		cur);	/*!< out: page cursor */
146 /**********************************************************//**
147 Invalidates a page cursor by setting the record pointer NULL. */
148 UNIV_INLINE
149 void
150 page_cur_invalidate(
151 /*================*/
152 	page_cur_t*	cur);	/*!< out: page cursor */
153 /**********************************************************//**
154 Moves the cursor to the next record on page. */
155 UNIV_INLINE
156 void
157 page_cur_move_to_next(
158 /*==================*/
159 	page_cur_t*	cur);	/*!< in/out: cursor; must not be after last */
160 /**********************************************************//**
161 Moves the cursor to the previous record on page. */
162 UNIV_INLINE
163 void
164 page_cur_move_to_prev(
165 /*==================*/
166 	page_cur_t*	cur);	/*!< in/out: cursor; not before first */
167 #ifndef UNIV_HOTBACKUP
168 /***********************************************************//**
169 Inserts a record next to page cursor. Returns pointer to inserted record if
170 succeed, i.e., enough space available, NULL otherwise. The cursor stays at
171 the same logical position, but the physical position may change if it is
172 pointing to a compressed page that was reorganized.
173 
174 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
175 if this is a compressed leaf page in a secondary index.
176 This has to be done either within the same mini-transaction,
177 or by invoking ibuf_reset_free_bits() before mtr_commit().
178 
179 @return	pointer to record if succeed, NULL otherwise */
180 UNIV_INLINE
181 rec_t*
182 page_cur_tuple_insert(
183 /*==================*/
184 	page_cur_t*	cursor,	/*!< in/out: a page cursor */
185 	const dtuple_t*	tuple,	/*!< in: pointer to a data tuple */
186 	dict_index_t*	index,	/*!< in: record descriptor */
187 	ulint**		offsets,/*!< out: offsets on *rec */
188 	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
189 	ulint		n_ext,	/*!< in: number of externally stored columns */
190 	mtr_t*		mtr)	/*!< in: mini-transaction handle, or NULL */
191 	MY_ATTRIBUTE((nonnull(1,2,3,4,5), warn_unused_result));
192 #endif /* !UNIV_HOTBACKUP */
193 /***********************************************************//**
194 Inserts a record next to page cursor. Returns pointer to inserted record if
195 succeed, i.e., enough space available, NULL otherwise. The cursor stays at
196 the same logical position, but the physical position may change if it is
197 pointing to a compressed page that was reorganized.
198 
199 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
200 if this is a compressed leaf page in a secondary index.
201 This has to be done either within the same mini-transaction,
202 or by invoking ibuf_reset_free_bits() before mtr_commit().
203 
204 @return	pointer to record if succeed, NULL otherwise */
205 UNIV_INLINE
206 rec_t*
207 page_cur_rec_insert(
208 /*================*/
209 	page_cur_t*	cursor,	/*!< in/out: a page cursor */
210 	const rec_t*	rec,	/*!< in: record to insert */
211 	dict_index_t*	index,	/*!< in: record descriptor */
212 	ulint*		offsets,/*!< in/out: rec_get_offsets(rec, index) */
213 	mtr_t*		mtr);	/*!< in: mini-transaction handle, or NULL */
214 /***********************************************************//**
215 Inserts a record next to page cursor on an uncompressed page.
216 Returns pointer to inserted record if succeed, i.e., enough
217 space available, NULL otherwise. The cursor stays at the same position.
218 @return	pointer to record if succeed, NULL otherwise */
219 UNIV_INTERN
220 rec_t*
221 page_cur_insert_rec_low(
222 /*====================*/
223 	rec_t*		current_rec,/*!< in: pointer to current record after
224 				which the new record is inserted */
225 	dict_index_t*	index,	/*!< in: record descriptor */
226 	const rec_t*	rec,	/*!< in: pointer to a physical record */
227 	ulint*		offsets,/*!< in/out: rec_get_offsets(rec, index) */
228 	mtr_t*		mtr)	/*!< in: mini-transaction handle, or NULL */
229 	MY_ATTRIBUTE((nonnull(1,2,3,4), warn_unused_result));
230 /***********************************************************//**
231 Inserts a record next to page cursor on a compressed and uncompressed
232 page. Returns pointer to inserted record if succeed, i.e.,
233 enough space available, NULL otherwise.
234 The cursor stays at the same position.
235 
236 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
237 if this is a compressed leaf page in a secondary index.
238 This has to be done either within the same mini-transaction,
239 or by invoking ibuf_reset_free_bits() before mtr_commit().
240 
241 @return	pointer to record if succeed, NULL otherwise */
242 UNIV_INTERN
243 rec_t*
244 page_cur_insert_rec_zip(
245 /*====================*/
246 	page_cur_t*	cursor,	/*!< in/out: page cursor */
247 	dict_index_t*	index,	/*!< in: record descriptor */
248 	const rec_t*	rec,	/*!< in: pointer to a physical record */
249 	ulint*		offsets,/*!< in/out: rec_get_offsets(rec, index) */
250 	mtr_t*		mtr)	/*!< in: mini-transaction handle, or NULL */
251 	MY_ATTRIBUTE((nonnull(1,2,3,4), warn_unused_result));
252 /*************************************************************//**
253 Copies records from page to a newly created page, from a given record onward,
254 including that record. Infimum and supremum records are not copied.
255 
256 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
257 if this is a compressed leaf page in a secondary index.
258 This has to be done either within the same mini-transaction,
259 or by invoking ibuf_reset_free_bits() before mtr_commit(). */
260 UNIV_INTERN
261 void
262 page_copy_rec_list_end_to_created_page(
263 /*===================================*/
264 	page_t*		new_page,	/*!< in/out: index page to copy to */
265 	rec_t*		rec,		/*!< in: first record to copy */
266 	dict_index_t*	index,		/*!< in: record descriptor */
267 	mtr_t*		mtr);		/*!< in: mtr */
268 /***********************************************************//**
269 Deletes a record at the page cursor. The cursor is moved to the
270 next record after the deleted one. */
271 UNIV_INTERN
272 void
273 page_cur_delete_rec(
274 /*================*/
275 	page_cur_t*		cursor,	/*!< in/out: a page cursor */
276 	const dict_index_t*	index,	/*!< in: record descriptor */
277 	const ulint*		offsets,/*!< in: rec_get_offsets(
278 					cursor->rec, index) */
279 	mtr_t*			mtr);	/*!< in: mini-transaction handle */
280 #ifndef UNIV_HOTBACKUP
281 /****************************************************************//**
282 Searches the right position for a page cursor.
283 @return	number of matched fields on the left */
284 UNIV_INLINE
285 ulint
286 page_cur_search(
287 /*============*/
288 	const buf_block_t*	block,	/*!< in: buffer block */
289 	const dict_index_t*	index,	/*!< in: record descriptor */
290 	const dtuple_t*		tuple,	/*!< in: data tuple */
291 	ulint			mode,	/*!< in: PAGE_CUR_L,
292 					PAGE_CUR_LE, PAGE_CUR_G, or
293 					PAGE_CUR_GE */
294 	page_cur_t*		cursor);/*!< out: page cursor */
295 /****************************************************************//**
296 Searches the right position for a page cursor. */
297 UNIV_INTERN
298 void
299 page_cur_search_with_match(
300 /*=======================*/
301 	const buf_block_t*	block,	/*!< in: buffer block */
302 	const dict_index_t*	index,	/*!< in: record descriptor */
303 	const dtuple_t*		tuple,	/*!< in: data tuple */
304 	ulint			mode,	/*!< in: PAGE_CUR_L,
305 					PAGE_CUR_LE, PAGE_CUR_G, or
306 					PAGE_CUR_GE */
307 	ulint*			iup_matched_fields,
308 					/*!< in/out: already matched
309 					fields in upper limit record */
310 	ulint*			iup_matched_bytes,
311 					/*!< in/out: already matched
312 					bytes in a field not yet
313 					completely matched */
314 	ulint*			ilow_matched_fields,
315 					/*!< in/out: already matched
316 					fields in lower limit record */
317 	ulint*			ilow_matched_bytes,
318 					/*!< in/out: already matched
319 					bytes in a field not yet
320 					completely matched */
321 	page_cur_t*		cursor);/*!< out: page cursor */
322 /***********************************************************//**
323 Positions a page cursor on a randomly chosen user record on a page. If there
324 are no user records, sets the cursor on the infimum record. */
325 UNIV_INTERN
326 void
327 page_cur_open_on_rnd_user_rec(
328 /*==========================*/
329 	buf_block_t*	block,	/*!< in: page */
330 	page_cur_t*	cursor);/*!< out: page cursor */
331 #endif /* !UNIV_HOTBACKUP */
332 /***********************************************************//**
333 Parses a log record of a record insert on a page.
334 @return	end of log record or NULL */
335 UNIV_INTERN
336 byte*
337 page_cur_parse_insert_rec(
338 /*======================*/
339 	ibool		is_short,/*!< in: TRUE if short inserts */
340 	byte*		ptr,	/*!< in: buffer */
341 	byte*		end_ptr,/*!< in: buffer end */
342 	buf_block_t*	block,	/*!< in: page or NULL */
343 	dict_index_t*	index,	/*!< in: record descriptor */
344 	mtr_t*		mtr);	/*!< in: mtr or NULL */
345 /**********************************************************//**
346 Parses a log record of copying a record list end to a new created page.
347 @return	end of log record or NULL */
348 UNIV_INTERN
349 byte*
350 page_parse_copy_rec_list_to_created_page(
351 /*=====================================*/
352 	byte*		ptr,	/*!< in: buffer */
353 	byte*		end_ptr,/*!< in: buffer end */
354 	buf_block_t*	block,	/*!< in: page or NULL */
355 	dict_index_t*	index,	/*!< in: record descriptor */
356 	mtr_t*		mtr);	/*!< in: mtr or NULL */
357 /***********************************************************//**
358 Parses log record of a record delete on a page.
359 @return	pointer to record end or NULL */
360 UNIV_INTERN
361 byte*
362 page_cur_parse_delete_rec(
363 /*======================*/
364 	byte*		ptr,	/*!< in: buffer */
365 	byte*		end_ptr,/*!< in: buffer end */
366 	buf_block_t*	block,	/*!< in: page or NULL */
367 	dict_index_t*	index,	/*!< in: record descriptor */
368 	mtr_t*		mtr);	/*!< in: mtr or NULL */
369 /*******************************************************//**
370 Removes the record from a leaf page. This function does not log
371 any changes. It is used by the IMPORT tablespace functions.
372 @return	true if success, i.e., the page did not become too empty */
373 UNIV_INTERN
374 bool
375 page_delete_rec(
376 /*============*/
377 	const dict_index_t*	index,	/*!< in: The index that the record
378 					belongs to */
379 	page_cur_t*		pcur,	/*!< in/out: page cursor on record
380 					to delete */
381 	page_zip_des_t*		page_zip,/*!< in: compressed page descriptor */
382 	const ulint*		offsets);/*!< in: offsets for record */
383 
384 /** Index page cursor */
385 
386 struct page_cur_t{
387 	byte*		rec;	/*!< pointer to a record on page */
388 	buf_block_t*	block;	/*!< pointer to the block containing rec */
389 };
390 
391 #ifndef UNIV_NONINL
392 #include "page0cur.ic"
393 #endif
394 
395 #endif
396