| 1 | /***************************************************************************** |
| 2 | |
| 3 | Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved. |
| 4 | Copyright (c) 2015, 2018, MariaDB Corporation. |
| 5 | |
| 6 | This program is free software; you can redistribute it and/or modify it under |
| 7 | the terms of the GNU General Public License as published by the Free Software |
| 8 | Foundation; version 2 of the License. |
| 9 | |
| 10 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU General Public License along with |
| 15 | this program; if not, write to the Free Software Foundation, Inc., |
| 16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
| 17 | |
| 18 | *****************************************************************************/ |
| 19 | |
| 20 | /********************************************************************//** |
| 21 | @file include/page0cur.ic |
| 22 | The page cursor |
| 23 | |
| 24 | Created 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 | /*********************************************************//** |
| 34 | Gets pointer to the page frame where the cursor is positioned. |
| 35 | @return page */ |
| 36 | UNIV_INLINE |
| 37 | page_t* |
| 38 | page_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 | /*********************************************************//** |
| 52 | Gets pointer to the buffer block where the cursor is positioned. |
| 53 | @return page */ |
| 54 | UNIV_INLINE |
| 55 | buf_block_t* |
| 56 | page_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 | /*********************************************************//** |
| 70 | Gets pointer to the page frame where the cursor is positioned. |
| 71 | @return page */ |
| 72 | UNIV_INLINE |
| 73 | page_zip_des_t* |
| 74 | page_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 | /*********************************************************//** |
| 82 | Gets the record where the cursor is positioned. |
| 83 | @return record */ |
| 84 | UNIV_INLINE |
| 85 | rec_t* |
| 86 | page_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 | /*********************************************************//** |
| 101 | Sets the cursor object to point before the first user record |
| 102 | on the page. */ |
| 103 | UNIV_INLINE |
| 104 | void |
| 105 | page_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 | /*********************************************************//** |
| 115 | Sets the cursor object to point after the last user record on |
| 116 | the page. */ |
| 117 | UNIV_INLINE |
| 118 | void |
| 119 | page_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 | /*********************************************************//** |
| 129 | Returns TRUE if the cursor is before first user record on page. |
| 130 | @return TRUE if at start */ |
| 131 | UNIV_INLINE |
| 132 | ibool |
| 133 | page_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 | /*********************************************************//** |
| 143 | Returns TRUE if the cursor is after last user record. |
| 144 | @return TRUE if at end */ |
| 145 | UNIV_INLINE |
| 146 | ibool |
| 147 | page_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 | /**********************************************************//** |
| 157 | Positions the cursor on the given record. */ |
| 158 | UNIV_INLINE |
| 159 | void |
| 160 | page_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 | /**********************************************************//** |
| 175 | Moves the cursor to the next record on page. */ |
| 176 | UNIV_INLINE |
| 177 | void |
| 178 | page_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 | /**********************************************************//** |
| 188 | Moves the cursor to the previous record on page. */ |
| 189 | UNIV_INLINE |
| 190 | void |
| 191 | page_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 */ |
| 207 | UNIV_INLINE |
| 208 | ulint |
| 209 | page_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 */ |
| 232 | UNIV_INLINE |
| 233 | ulint |
| 234 | page_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 | /***********************************************************//** |
| 244 | Inserts a record next to page cursor. Returns pointer to inserted record if |
| 245 | succeed, i.e., enough space available, NULL otherwise. The cursor stays at |
| 246 | the same logical position, but the physical position may change if it is |
| 247 | pointing to a compressed page that was reorganized. |
| 248 | |
| 249 | IMPORTANT: The caller will have to update IBUF_BITMAP_FREE |
| 250 | if this is a compressed leaf page in a secondary index. |
| 251 | This has to be done either within the same mini-transaction, |
| 252 | or by invoking ibuf_reset_free_bits() before mtr_commit(). |
| 253 | |
| 254 | @return pointer to record if succeed, NULL otherwise */ |
| 255 | UNIV_INLINE |
| 256 | rec_t* |
| 257 | page_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 | 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 | ULINT_UNDEFINED, heap); |
| 283 | |
| 284 | if (buf_block_get_page_zip(cursor->block)) { |
| 285 | rec = page_cur_insert_rec_zip( |
| 286 | cursor, index, rec, *offsets, mtr); |
| 287 | } else { |
| 288 | rec = page_cur_insert_rec_low(cursor->rec, |
| 289 | index, rec, *offsets, mtr); |
| 290 | } |
| 291 | |
| 292 | ut_ad(!rec || !cmp_dtuple_rec(tuple, rec, *offsets)); |
| 293 | return(rec); |
| 294 | } |
| 295 | |
| 296 | /***********************************************************//** |
| 297 | Inserts a record next to page cursor. Returns pointer to inserted record if |
| 298 | succeed, i.e., enough space available, NULL otherwise. The cursor stays at |
| 299 | the same logical position, but the physical position may change if it is |
| 300 | pointing to a compressed page that was reorganized. |
| 301 | |
| 302 | IMPORTANT: The caller will have to update IBUF_BITMAP_FREE |
| 303 | if this is a compressed leaf page in a secondary index. |
| 304 | This has to be done either within the same mini-transaction, |
| 305 | or by invoking ibuf_reset_free_bits() before mtr_commit(). |
| 306 | |
| 307 | @return pointer to record if succeed, NULL otherwise */ |
| 308 | UNIV_INLINE |
| 309 | rec_t* |
| 310 | page_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 | |