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