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