1/***************************************************************************** 2 3Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved. 4 5This program is free software; you can redistribute it and/or modify 6it under the terms of the GNU General Public License, version 2.0, 7as published by the Free Software Foundation. 8 9This program is also distributed with certain software (including 10but not limited to OpenSSL) that is licensed under separate terms, 11as designated in a particular file or component or in included license 12documentation. The authors of MySQL hereby grant you an additional 13permission to link the program and your derivative works with the 14separately licensed software that they have included with MySQL. 15 16This program is distributed in the hope that it will be useful, 17but WITHOUT ANY WARRANTY; without even the implied warranty of 18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19GNU General Public License, version 2.0, for more details. 20 21You should have received a copy of the GNU General Public License along with 22this program; if not, write to the Free Software Foundation, Inc., 2351 Franklin Street, Suite 500, Boston, MA 02110-1335 USA 24 25*****************************************************************************/ 26 27/********************************************************************//** 28@file include/page0cur.ic 29The page cursor 30 31Created 10/4/1994 Heikki Tuuri 32*************************************************************************/ 33 34#include "page0page.h" 35#include "buf0types.h" 36 37#ifdef UNIV_DEBUG 38# include "rem0cmp.h" 39 40/*********************************************************//** 41Gets pointer to the page frame where the cursor is positioned. 42@return page */ 43UNIV_INLINE 44page_t* 45page_cur_get_page( 46/*==============*/ 47 page_cur_t* cur) /*!< in: page cursor */ 48{ 49 ut_ad(cur); 50 ut_ad(page_align(cur->rec) == cur->block->frame); 51 52 return(page_align(cur->rec)); 53} 54 55/*********************************************************//** 56Gets pointer to the buffer block where the cursor is positioned. 57@return page */ 58UNIV_INLINE 59buf_block_t* 60page_cur_get_block( 61/*===============*/ 62 page_cur_t* cur) /*!< in: page cursor */ 63{ 64 ut_ad(cur); 65 ut_ad(page_align(cur->rec) == cur->block->frame); 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 ut_ad(page_align(cur->rec) == cur->block->frame); 92 93 return(cur->rec); 94} 95#endif /* UNIV_DEBUG */ 96 97/*********************************************************//** 98Sets the cursor object to point before the first user record 99on the page. */ 100UNIV_INLINE 101void 102page_cur_set_before_first( 103/*======================*/ 104 const buf_block_t* block, /*!< in: index page */ 105 page_cur_t* cur) /*!< in: cursor */ 106{ 107 cur->block = (buf_block_t*) block; 108 cur->rec = page_get_infimum_rec(buf_block_get_frame(cur->block)); 109} 110 111/*********************************************************//** 112Sets the cursor object to point after the last user record on 113the page. */ 114UNIV_INLINE 115void 116page_cur_set_after_last( 117/*====================*/ 118 const buf_block_t* block, /*!< in: index page */ 119 page_cur_t* cur) /*!< in: cursor */ 120{ 121 cur->block = (buf_block_t*) block; 122 cur->rec = page_get_supremum_rec(buf_block_get_frame(cur->block)); 123} 124 125/*********************************************************//** 126Returns TRUE if the cursor is before first user record on page. 127@return TRUE if at start */ 128UNIV_INLINE 129ibool 130page_cur_is_before_first( 131/*=====================*/ 132 const page_cur_t* cur) /*!< in: cursor */ 133{ 134 ut_ad(cur); 135 ut_ad(page_align(cur->rec) == cur->block->frame); 136 return(page_rec_is_infimum(cur->rec)); 137} 138 139/*********************************************************//** 140Returns TRUE if the cursor is after last user record. 141@return TRUE if at end */ 142UNIV_INLINE 143ibool 144page_cur_is_after_last( 145/*===================*/ 146 const page_cur_t* cur) /*!< in: cursor */ 147{ 148 ut_ad(cur); 149 ut_ad(page_align(cur->rec) == cur->block->frame); 150 return(page_rec_is_supremum(cur->rec)); 151} 152 153/**********************************************************//** 154Positions the cursor on the given record. */ 155UNIV_INLINE 156void 157page_cur_position( 158/*==============*/ 159 const rec_t* rec, /*!< in: record on a page */ 160 const buf_block_t* block, /*!< in: buffer block containing 161 the record */ 162 page_cur_t* cur) /*!< out: page cursor */ 163{ 164 ut_ad(rec && block && cur); 165 ut_ad(page_align(rec) == block->frame); 166 167 cur->rec = (rec_t*) rec; 168 cur->block = (buf_block_t*) block; 169} 170 171/**********************************************************//** 172Invalidates a page cursor by setting the record pointer NULL. */ 173UNIV_INLINE 174void 175page_cur_invalidate( 176/*================*/ 177 page_cur_t* cur) /*!< out: page cursor */ 178{ 179 ut_ad(cur); 180 181 cur->rec = NULL; 182 cur->block = NULL; 183} 184 185/**********************************************************//** 186Moves the cursor to the next record on page. */ 187UNIV_INLINE 188void 189page_cur_move_to_next( 190/*==================*/ 191 page_cur_t* cur) /*!< in/out: cursor; must not be after last */ 192{ 193 ut_ad(!page_cur_is_after_last(cur)); 194 195 cur->rec = page_rec_get_next(cur->rec); 196} 197 198/**********************************************************//** 199Moves the cursor to the previous record on page. */ 200UNIV_INLINE 201void 202page_cur_move_to_prev( 203/*==================*/ 204 page_cur_t* cur) /*!< in/out: page cursor, not before first */ 205{ 206 ut_ad(!page_cur_is_before_first(cur)); 207 208 cur->rec = page_rec_get_prev(cur->rec); 209} 210 211#ifndef UNIV_HOTBACKUP 212/****************************************************************//** 213Searches the right position for a page cursor. 214@return number of matched fields on the left */ 215UNIV_INLINE 216ulint 217page_cur_search( 218/*============*/ 219 const buf_block_t* block, /*!< in: buffer block */ 220 const dict_index_t* index, /*!< in: record descriptor */ 221 const dtuple_t* tuple, /*!< in: data tuple */ 222 ulint mode, /*!< in: PAGE_CUR_L, 223 PAGE_CUR_LE, PAGE_CUR_G, or 224 PAGE_CUR_GE */ 225 page_cur_t* cursor) /*!< out: page cursor */ 226{ 227 ulint low_matched_fields = 0; 228 ulint low_matched_bytes = 0; 229 ulint up_matched_fields = 0; 230 ulint up_matched_bytes = 0; 231 232 ut_ad(dtuple_check_typed(tuple)); 233 234 page_cur_search_with_match(block, index, tuple, mode, 235 &up_matched_fields, 236 &up_matched_bytes, 237 &low_matched_fields, 238 &low_matched_bytes, 239 cursor); 240 return(low_matched_fields); 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 ulint** 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 ulint size 268 = rec_get_converted_size(index, tuple, n_ext); 269 rec_t* rec; 270 271 if (!*heap) { 272 *heap = mem_heap_create(size 273 + (4 + REC_OFFS_HEADER_SIZE 274 + dtuple_get_n_fields(tuple)) 275 * sizeof **offsets); 276 } 277 278 rec = rec_convert_dtuple_to_rec((byte*) mem_heap_alloc(*heap, size), 279 index, tuple, n_ext); 280 *offsets = rec_get_offsets( 281 rec, index, *offsets, ULINT_UNDEFINED, heap); 282 283 if (buf_block_get_page_zip(cursor->block)) { 284 rec = page_cur_insert_rec_zip( 285 cursor, index, rec, *offsets, mtr); 286 } else { 287 rec = page_cur_insert_rec_low(cursor->rec, 288 index, rec, *offsets, mtr); 289 } 290 291 ut_ad(!rec || !cmp_dtuple_rec(tuple, rec, *offsets)); 292 return(rec); 293} 294#endif /* !UNIV_HOTBACKUP */ 295 296/***********************************************************//** 297Inserts a record next to page cursor. Returns pointer to inserted record if 298succeed, i.e., enough space available, NULL otherwise. The cursor stays at 299the same logical position, but the physical position may change if it is 300pointing to a compressed page that was reorganized. 301 302IMPORTANT: The caller will have to update IBUF_BITMAP_FREE 303if this is a compressed leaf page in a secondary index. 304This has to be done either within the same mini-transaction, 305or by invoking ibuf_reset_free_bits() before mtr_commit(). 306 307@return pointer to record if succeed, NULL otherwise */ 308UNIV_INLINE 309rec_t* 310page_cur_rec_insert( 311/*================*/ 312 page_cur_t* cursor, /*!< in/out: a page cursor */ 313 const rec_t* rec, /*!< in: record to insert */ 314 dict_index_t* index, /*!< in: record descriptor */ 315 ulint* offsets,/*!< in/out: rec_get_offsets(rec, index) */ 316 mtr_t* mtr) /*!< in: mini-transaction handle, or NULL */ 317{ 318 if (buf_block_get_page_zip(cursor->block)) { 319 return(page_cur_insert_rec_zip( 320 cursor, index, rec, offsets, mtr)); 321 } else { 322 return(page_cur_insert_rec_low(cursor->rec, 323 index, rec, offsets, mtr)); 324 } 325} 326