1/***************************************************************************** 2 3Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved. 4Copyright (c) 2015, 2021, 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, Fifth Floor, Boston, MA 02110-1335 USA 17 18*****************************************************************************/ 19 20/********************************************************************//** 21@file include/page0cur.ic 22The page cursor 23 24Created 10/4/1994 Heikki Tuuri 25*************************************************************************/ 26 27#include "page0page.h" 28#include "buf0types.h" 29 30#ifdef UNIV_DEBUG 31# include "rem0cmp.h" 32 33/*********************************************************//** 34Gets pointer to the page frame where the cursor is positioned. 35@return page */ 36UNIV_INLINE 37page_t* 38page_cur_get_page( 39/*==============*/ 40 page_cur_t* cur) /*!< in: page cursor */ 41{ 42 ut_ad(cur); 43 44 if (cur->rec) { 45 ut_ad(page_align(cur->rec) == cur->block->frame); 46 } 47 48 return(page_align(cur->rec)); 49} 50 51/*********************************************************//** 52Gets pointer to the buffer block where the cursor is positioned. 53@return page */ 54UNIV_INLINE 55buf_block_t* 56page_cur_get_block( 57/*===============*/ 58 page_cur_t* cur) /*!< in: page cursor */ 59{ 60 ut_ad(cur); 61 62 if (cur->rec) { 63 ut_ad(page_align(cur->rec) == cur->block->frame); 64 } 65 66 return(cur->block); 67} 68 69/*********************************************************//** 70Gets pointer to the page frame where the cursor is positioned. 71@return page */ 72UNIV_INLINE 73page_zip_des_t* 74page_cur_get_page_zip( 75/*==================*/ 76 page_cur_t* cur) /*!< in: page cursor */ 77{ 78 return(buf_block_get_page_zip(page_cur_get_block(cur))); 79} 80 81/*********************************************************//** 82Gets the record where the cursor is positioned. 83@return record */ 84UNIV_INLINE 85rec_t* 86page_cur_get_rec( 87/*=============*/ 88 page_cur_t* cur) /*!< in: page cursor */ 89{ 90 ut_ad(cur); 91 92 if (cur->rec) { 93 ut_ad(page_align(cur->rec) == cur->block->frame); 94 } 95 96 return(cur->rec); 97} 98#endif /* UNIV_DEBUG */ 99 100/*********************************************************//** 101Sets the cursor object to point before the first user record 102on the page. */ 103UNIV_INLINE 104void 105page_cur_set_before_first( 106/*======================*/ 107 const buf_block_t* block, /*!< in: index page */ 108 page_cur_t* cur) /*!< in: cursor */ 109{ 110 cur->block = (buf_block_t*) block; 111 cur->rec = page_get_infimum_rec(buf_block_get_frame(cur->block)); 112} 113 114/*********************************************************//** 115Sets the cursor object to point after the last user record on 116the page. */ 117UNIV_INLINE 118void 119page_cur_set_after_last( 120/*====================*/ 121 const buf_block_t* block, /*!< in: index page */ 122 page_cur_t* cur) /*!< in: cursor */ 123{ 124 cur->block = (buf_block_t*) block; 125 cur->rec = page_get_supremum_rec(buf_block_get_frame(cur->block)); 126} 127 128/*********************************************************//** 129Returns TRUE if the cursor is before first user record on page. 130@return TRUE if at start */ 131UNIV_INLINE 132ibool 133page_cur_is_before_first( 134/*=====================*/ 135 const page_cur_t* cur) /*!< in: cursor */ 136{ 137 ut_ad(cur); 138 ut_ad(page_align(cur->rec) == cur->block->frame); 139 return(page_rec_is_infimum(cur->rec)); 140} 141 142/*********************************************************//** 143Returns TRUE if the cursor is after last user record. 144@return TRUE if at end */ 145UNIV_INLINE 146ibool 147page_cur_is_after_last( 148/*===================*/ 149 const page_cur_t* cur) /*!< in: cursor */ 150{ 151 ut_ad(cur); 152 ut_ad(page_align(cur->rec) == cur->block->frame); 153 return(page_rec_is_supremum(cur->rec)); 154} 155 156/**********************************************************//** 157Positions the cursor on the given record. */ 158UNIV_INLINE 159void 160page_cur_position( 161/*==============*/ 162 const rec_t* rec, /*!< in: record on a page */ 163 const buf_block_t* block, /*!< in: buffer block containing 164 the record */ 165 page_cur_t* cur) /*!< out: page cursor */ 166{ 167 ut_ad(rec && block && cur); 168 ut_ad(page_align(rec) == block->frame); 169 170 cur->rec = (rec_t*) rec; 171 cur->block = (buf_block_t*) block; 172} 173 174/**********************************************************//** 175Moves the cursor to the next record on page. */ 176UNIV_INLINE 177void 178page_cur_move_to_next( 179/*==================*/ 180 page_cur_t* cur) /*!< in/out: cursor; must not be after last */ 181{ 182 ut_ad(!page_cur_is_after_last(cur)); 183 184 cur->rec = page_rec_get_next(cur->rec); 185} 186 187/**********************************************************//** 188Moves the cursor to the previous record on page. */ 189UNIV_INLINE 190void 191page_cur_move_to_prev( 192/*==================*/ 193 page_cur_t* cur) /*!< in/out: page cursor, not before first */ 194{ 195 ut_ad(!page_cur_is_before_first(cur)); 196 197 cur->rec = page_rec_get_prev(cur->rec); 198} 199 200/** Search the right position for a page cursor. 201@param[in] block buffer block 202@param[in] index index tree 203@param[in] tuple data tuple 204@param[in] mode PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G, or PAGE_CUR_GE 205@param[out] cursor page cursor 206@return number of matched fields on the left */ 207UNIV_INLINE 208ulint 209page_cur_search( 210 const buf_block_t* block, 211 const dict_index_t* index, 212 const dtuple_t* tuple, 213 page_cur_mode_t mode, 214 page_cur_t* cursor) 215{ 216 ulint low_match = 0; 217 ulint up_match = 0; 218 219 ut_ad(dtuple_check_typed(tuple)); 220 221 page_cur_search_with_match(block, index, tuple, mode, 222 &up_match, &low_match, cursor, NULL); 223 return(low_match); 224} 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 */ 232UNIV_INLINE 233ulint 234page_cur_search( 235 const buf_block_t* block, 236 const dict_index_t* index, 237 const dtuple_t* tuple, 238 page_cur_t* cursor) 239{ 240 return(page_cur_search(block, index, tuple, PAGE_CUR_LE, cursor)); 241} 242 243/***********************************************************//** 244Inserts a record next to page cursor. Returns pointer to inserted record if 245succeed, i.e., enough space available, NULL otherwise. The cursor stays at 246the same logical position, but the physical position may change if it is 247pointing to a compressed page that was reorganized. 248 249IMPORTANT: The caller will have to update IBUF_BITMAP_FREE 250if this is a compressed leaf page in a secondary index. 251This has to be done either within the same mini-transaction, 252or by invoking ibuf_reset_free_bits() before mtr_commit(). 253 254@return pointer to record if succeed, NULL otherwise */ 255UNIV_INLINE 256rec_t* 257page_cur_tuple_insert( 258/*==================*/ 259 page_cur_t* cursor, /*!< in/out: a page cursor */ 260 const dtuple_t* tuple, /*!< in: pointer to a data tuple */ 261 dict_index_t* index, /*!< in: record descriptor */ 262 rec_offs** offsets,/*!< out: offsets on *rec */ 263 mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */ 264 ulint n_ext, /*!< in: number of externally stored columns */ 265 mtr_t* mtr) /*!< in: mini-transaction handle, or NULL */ 266{ 267 rec_t* rec; 268 ulint size = rec_get_converted_size(index, tuple, n_ext); 269 270 if (!*heap) { 271 *heap = mem_heap_create(size 272 + (4 + REC_OFFS_HEADER_SIZE 273 + dtuple_get_n_fields(tuple)) 274 * sizeof **offsets); 275 } 276 277 rec = rec_convert_dtuple_to_rec((byte*) mem_heap_alloc(*heap, size), 278 index, tuple, n_ext); 279 280 *offsets = rec_get_offsets(rec, index, *offsets, 281 page_is_leaf(cursor->block->frame) 282 ? index->n_core_fields : 0, 283 ULINT_UNDEFINED, heap); 284 285 if (buf_block_get_page_zip(cursor->block)) { 286 rec = page_cur_insert_rec_zip( 287 cursor, index, rec, *offsets, mtr); 288 } else { 289 rec = page_cur_insert_rec_low(cursor->rec, 290 index, rec, *offsets, mtr); 291 } 292 293 ut_ad(!rec || !cmp_dtuple_rec(tuple, rec, *offsets)); 294 return(rec); 295} 296 297/***********************************************************//** 298Inserts a record next to page cursor. Returns pointer to inserted record if 299succeed, i.e., enough space available, NULL otherwise. The cursor stays at 300the same logical position, but the physical position may change if it is 301pointing to a compressed page that was reorganized. 302 303IMPORTANT: The caller will have to update IBUF_BITMAP_FREE 304if this is a compressed leaf page in a secondary index. 305This has to be done either within the same mini-transaction, 306or by invoking ibuf_reset_free_bits() before mtr_commit(). 307 308@return pointer to record if succeed, NULL otherwise */ 309UNIV_INLINE 310rec_t* 311page_cur_rec_insert( 312/*================*/ 313 page_cur_t* cursor, /*!< in/out: a page cursor */ 314 const rec_t* rec, /*!< in: record to insert */ 315 dict_index_t* index, /*!< in: record descriptor */ 316 rec_offs* offsets,/*!< in/out: rec_get_offsets(rec, index) */ 317 mtr_t* mtr) /*!< in: mini-transaction handle, or NULL */ 318{ 319 if (buf_block_get_page_zip(cursor->block)) { 320 return(page_cur_insert_rec_zip( 321 cursor, index, rec, offsets, mtr)); 322 } else { 323 return(page_cur_insert_rec_low(cursor->rec, 324 index, rec, offsets, mtr)); 325 } 326} 327