1 /*****************************************************************************
2 
3 Copyright (c) 1994, 2020, 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 #include <stddef.h>
28 #include <sys/types.h>
29 
30 /** @file include/btr0cur.h
31  The index tree cursor
32 
33  Created 10/16/1994 Heikki Tuuri
34  *******************************************************/
35 
36 #ifndef btr0cur_h
37 #define btr0cur_h
38 
39 #include "btr0types.h"
40 #include "dict0dict.h"
41 #include "gis0type.h"
42 #include "page0cur.h"
43 #include "univ.i"
44 
45 /** Mode flags for btr_cur operations; these can be ORed */
46 enum {
47   /** do no undo logging */
48   BTR_NO_UNDO_LOG_FLAG = 1,
49   /** do no record lock checking */
50   BTR_NO_LOCKING_FLAG = 2,
51   /** sys fields will be found in the update vector or inserted
52   entry */
53   BTR_KEEP_SYS_FLAG = 4,
54   /** btr_cur_pessimistic_update() must keep cursor position
55   when moving columns to big_rec */
56   BTR_KEEP_POS_FLAG = 8,
57   /** the caller is creating the index or wants to bypass the
58   index->info.online creation log */
59   BTR_CREATE_FLAG = 16,
60   /** the caller of btr_cur_optimistic_update() or
61   btr_cur_update_in_place() will take care of
62   updating IBUF_BITMAP_FREE */
63   BTR_KEEP_IBUF_BITMAP = 32
64 };
65 
66 /* btr_cur_latch_leaves() returns latched blocks and savepoints. */
67 struct btr_latch_leaves_t {
68   /* left block, target block and right block */
69   buf_block_t *blocks[3];
70   ulint savepoints[3];
71 };
72 
73 #ifndef UNIV_HOTBACKUP
74 #include "ha0ha.h"
75 #include "que0types.h"
76 #include "row0types.h"
77 #endif /* !UNIV_HOTBACKUP */
78 
79 #define BTR_CUR_ADAPT
80 #define BTR_CUR_HASH_ADAPT
81 
82 #ifdef UNIV_DEBUG
83 /** Returns the page cursor component of a tree cursor.
84  @return pointer to page cursor component */
85 UNIV_INLINE
86 page_cur_t *btr_cur_get_page_cur(
87     const btr_cur_t *cursor); /*!< in: tree cursor */
88 /** Returns the buffer block on which the tree cursor is positioned.
89  @return pointer to buffer block */
90 UNIV_INLINE
91 buf_block_t *btr_cur_get_block(const btr_cur_t *cursor); /*!< in: tree cursor */
92 /** Returns the record pointer of a tree cursor.
93  @return pointer to record */
94 UNIV_INLINE
95 rec_t *btr_cur_get_rec(const btr_cur_t *cursor); /*!< in: tree cursor */
96 #else                                            /* UNIV_DEBUG */
97 #define btr_cur_get_page_cur(cursor) (&(cursor)->page_cur)
98 #define btr_cur_get_block(cursor) ((cursor)->page_cur.block)
99 #define btr_cur_get_rec(cursor) ((cursor)->page_cur.rec)
100 #endif /* UNIV_DEBUG */
101 /** Returns the compressed page on which the tree cursor is positioned.
102  @return pointer to compressed page, or NULL if the page is not compressed */
103 UNIV_INLINE
104 page_zip_des_t *btr_cur_get_page_zip(btr_cur_t *cursor); /*!< in: tree cursor */
105 /** Returns the page of a tree cursor.
106  @return pointer to page */
107 UNIV_INLINE
108 page_t *btr_cur_get_page(btr_cur_t *cursor); /*!< in: tree cursor */
109 /** Returns the index of a cursor.
110  @param cursor b-tree cursor
111  @return index */
112 #define btr_cur_get_index(cursor) ((cursor)->index)
113 
114 /** Positions a tree cursor at a given record.
115 @param[in]	index	index
116 @param[in]	rec	record in tree
117 @param[in]	block	buffer block of rec
118 @param[in]	cursor	cursor */
119 UNIV_INLINE
120 void btr_cur_position(dict_index_t *index, rec_t *rec, buf_block_t *block,
121                       btr_cur_t *cursor);
122 
123 /** Optimistically latches the leaf page or pages requested.
124 @param[in]	block		guessed buffer block
125 @param[in]	modify_clock	modify clock value
126 @param[in,out]	latch_mode	BTR_SEARCH_LEAF, ...
127 @param[in,out]	cursor		cursor
128 @param[in]	file		file name
129 @param[in]	line		line where called
130 @param[in]	mtr		mini-transaction
131 @return true if success */
132 bool btr_cur_optimistic_latch_leaves(buf_block_t *block,
133                                      ib_uint64_t modify_clock,
134                                      ulint *latch_mode, btr_cur_t *cursor,
135                                      const char *file, ulint line, mtr_t *mtr);
136 
137 /** Searches an index tree and positions a tree cursor on a given level.
138  NOTE: n_fields_cmp in tuple must be set so that it cannot be compared
139  to node pointer page number fields on the upper levels of the tree!
140  Note that if mode is PAGE_CUR_LE, which is used in inserts, then
141  cursor->up_match and cursor->low_match both will have sensible values.
142  If mode is PAGE_CUR_GE, then up_match will a have a sensible value. */
143 void btr_cur_search_to_nth_level(
144     dict_index_t *index,   /*!< in: index */
145     ulint level,           /*!< in: the tree level of search */
146     const dtuple_t *tuple, /*!< in: data tuple; NOTE: n_fields_cmp in
147                            tuple must be set so that it cannot get
148                            compared to the node ptr page number field! */
149     page_cur_mode_t mode,  /*!< in: PAGE_CUR_L, ...;
150                            NOTE that if the search is made using a unique
151                            prefix of a record, mode should be PAGE_CUR_LE,
152                            not PAGE_CUR_GE, as the latter may end up on
153                            the previous page of the record! Inserts
154                            should always be made using PAGE_CUR_LE to
155                            search the position! */
156     ulint latch_mode,      /*!< in: BTR_SEARCH_LEAF, ..., ORed with
157                        at most one of BTR_INSERT, BTR_DELETE_MARK,
158                        BTR_DELETE, or BTR_ESTIMATE;
159                        cursor->left_block is used to store a pointer
160                        to the left neighbor page, in the cases
161                        BTR_SEARCH_PREV and BTR_MODIFY_PREV;
162                        NOTE that if has_search_latch
163                        is != 0, we maybe do not have a latch set
164                        on the cursor page, we assume
165                        the caller uses his search latch
166                        to protect the record! */
167     btr_cur_t *cursor,     /*!< in/out: tree cursor; the cursor page is
168                            s- or x-latched, but see also above! */
169     ulint has_search_latch,
170     /*!< in: latch mode the caller
171     currently has on search system:
172     RW_S_LATCH, or 0 */
173     const char *file, /*!< in: file name */
174     ulint line,       /*!< in: line where called */
175     mtr_t *mtr);      /*!< in: mtr */
176 
177 /** Searches an index tree and positions a tree cursor on a given level.
178 This function will avoid placing latches the travesal path and so
179 should be used only for cases where-in latching is not needed.
180 
181 @param[in]	index	index
182 @param[in]	level	the tree level of search
183 @param[in]	tuple	data tuple; Note: n_fields_cmp in compared
184                         to the node ptr page node field
185 @param[in]	mode	PAGE_CUR_L, ....
186                         Insert should always be made using PAGE_CUR_LE
187                         to search the position.
188 @param[in,out]	cursor	tree cursor; points to record of interest.
189 @param[in]	file	file name
190 @param[in]	line	line where called from
191 @param[in,out]	mtr	mtr
192 @param[in]	mark_dirty
193                         if true then mark the block as dirty */
194 void btr_cur_search_to_nth_level_with_no_latch(
195     dict_index_t *index, ulint level, const dtuple_t *tuple,
196     page_cur_mode_t mode, btr_cur_t *cursor, const char *file, ulint line,
197     mtr_t *mtr, bool mark_dirty = true);
198 
199 /** Opens a cursor at either end of an index. */
200 void btr_cur_open_at_index_side_func(
201     bool from_left,      /*!< in: true if open to the low end,
202                          false if to the high end */
203     dict_index_t *index, /*!< in: index */
204     ulint latch_mode,    /*!< in: latch mode */
205     btr_cur_t *cursor,   /*!< in/out: cursor */
206     ulint level,         /*!< in: level to search for
207                          (0=leaf) */
208     const char *file,    /*!< in: file name */
209     ulint line,          /*!< in: line where called */
210     mtr_t *mtr);         /*!< in/out: mini-transaction */
211 #define btr_cur_open_at_index_side(f, i, l, c, lv, m) \
212   btr_cur_open_at_index_side_func(f, i, l, c, lv, __FILE__, __LINE__, m)
213 
214 /** Opens a cursor at either end of an index.
215 Avoid taking latches on buffer, just pin (by incrementing fix_count)
216 to keep them in buffer pool. This mode is used by intrinsic table
217 as they are not shared and so there is no need of latching.
218 @param[in]	from_left	true if open to low end, false if open
219                                 to high end.
220 @param[in]	index		index
221 @param[in,out]	cursor		cursor
222 @param[in]	file		file name
223 @param[in]	line		line where called
224 @param[in,out]	mtr		mini transaction
225 */
226 void btr_cur_open_at_index_side_with_no_latch_func(
227     bool from_left, dict_index_t *index, btr_cur_t *cursor, ulint level,
228     const char *file, ulint line, mtr_t *mtr);
229 #define btr_cur_open_at_index_side_with_no_latch(f, i, c, lv, m)       \
230   btr_cur_open_at_index_side_with_no_latch_func(f, i, c, lv, __FILE__, \
231                                                 __LINE__, m)
232 
233 /** Positions a cursor at a randomly chosen position within a B-tree.
234  @return true if the index is available and we have put the cursor, false
235  if the index is unavailable */
236 bool btr_cur_open_at_rnd_pos_func(
237     dict_index_t *index, /*!< in: index */
238     ulint latch_mode,    /*!< in: BTR_SEARCH_LEAF, ... */
239     btr_cur_t *cursor,   /*!< in/out: B-tree cursor */
240     const char *file,    /*!< in: file name */
241     ulint line,          /*!< in: line where called */
242     mtr_t *mtr);         /*!< in: mtr */
243 #define btr_cur_open_at_rnd_pos(i, l, c, m) \
244   btr_cur_open_at_rnd_pos_func(i, l, c, __FILE__, __LINE__, m)
245 /** Tries to perform an insert to a page in an index tree, next to cursor.
246  It is assumed that mtr holds an x-latch on the page. The operation does
247  not succeed if there is too little space on the page. If there is just
248  one record on the page, the insert will always succeed; this is to
249  prevent trying to split a page with just one record.
250  @return DB_SUCCESS, DB_WAIT_LOCK, DB_FAIL, or error number */
251 dberr_t btr_cur_optimistic_insert(
252     ulint flags,         /*!< in: undo logging and locking flags: if not
253                          zero, the parameters index and thr should be
254                          specified */
255     btr_cur_t *cursor,   /*!< in: cursor on page after which to insert;
256                          cursor stays valid */
257     ulint **offsets,     /*!< out: offsets on *rec */
258     mem_heap_t **heap,   /*!< in/out: pointer to memory heap, or NULL */
259     dtuple_t *entry,     /*!< in/out: entry to insert */
260     rec_t **rec,         /*!< out: pointer to inserted record if
261                          succeed */
262     big_rec_t **big_rec, /*!< out: big rec vector whose fields have to
263                          be stored externally by the caller, or
264                          NULL */
265     que_thr_t *thr,      /*!< in: query thread or NULL */
266     mtr_t *mtr)          /*!< in/out: mini-transaction;
267                          if this function returns DB_SUCCESS on
268                          a leaf page of a secondary index in a
269                          compressed tablespace, the caller must
270                          mtr_commit(mtr) before latching
271                          any further pages */
272     MY_ATTRIBUTE((warn_unused_result));
273 /** Performs an insert on a page of an index tree. It is assumed that mtr
274  holds an x-latch on the tree and on the cursor page. If the insert is
275  made on the leaf level, to avoid deadlocks, mtr must also own x-latches
276  to brothers of page, if those brothers exist.
277  @return DB_SUCCESS or error number */
278 dberr_t btr_cur_pessimistic_insert(
279     uint32_t flags,      /*!< in: undo logging and locking flags: if not
280                          zero, the parameter thr should be
281                          specified; if no undo logging is specified,
282                          then the caller must have reserved enough
283                          free extents in the file space so that the
284                          insertion will certainly succeed */
285     btr_cur_t *cursor,   /*!< in: cursor after which to insert;
286                          cursor stays valid */
287     ulint **offsets,     /*!< out: offsets on *rec */
288     mem_heap_t **heap,   /*!< in/out: pointer to memory heap
289                          that can be emptied, or NULL */
290     dtuple_t *entry,     /*!< in/out: entry to insert */
291     rec_t **rec,         /*!< out: pointer to inserted record if
292                          succeed */
293     big_rec_t **big_rec, /*!< out: big rec vector whose fields have to
294                          be stored externally by the caller, or
295                          NULL */
296     que_thr_t *thr,      /*!< in: query thread or NULL */
297     mtr_t *mtr)          /*!< in/out: mini-transaction */
298     MY_ATTRIBUTE((warn_unused_result));
299 /** See if there is enough place in the page modification log to log
300  an update-in-place.
301 
302  @retval false if out of space; IBUF_BITMAP_FREE will be reset
303  outside mtr if the page was recompressed
304  @retval true if enough place;
305 
306  IMPORTANT: The caller will have to update IBUF_BITMAP_FREE if this is
307  a secondary index leaf page. This has to be done either within the
308  same mini-transaction, or by invoking ibuf_reset_free_bits() before
309  mtr_commit(mtr). */
310 bool btr_cur_update_alloc_zip_func(
311     page_zip_des_t *page_zip, /*!< in/out: compressed page */
312     page_cur_t *cursor,       /*!< in/out: B-tree page cursor */
313     dict_index_t *index,      /*!< in: the index corresponding to cursor */
314 #ifdef UNIV_DEBUG
315     ulint *offsets, /*!< in/out: offsets of the cursor record */
316 #endif              /* UNIV_DEBUG */
317     ulint length,   /*!< in: size needed */
318     bool create,    /*!< in: true=delete-and-insert,
319                     false=update-in-place */
320     mtr_t *mtr)     /*!< in/out: mini-transaction */
321     MY_ATTRIBUTE((warn_unused_result));
322 #ifdef UNIV_DEBUG
323 #define btr_cur_update_alloc_zip(page_zip, cursor, index, offsets, len, cr, \
324                                  mtr)                                       \
325   btr_cur_update_alloc_zip_func(page_zip, cursor, index, offsets, len, cr, mtr)
326 #else /* UNIV_DEBUG */
327 #define btr_cur_update_alloc_zip(page_zip, cursor, index, offsets, len, cr, \
328                                  mtr)                                       \
329   btr_cur_update_alloc_zip_func(page_zip, cursor, index, len, cr, mtr)
330 #endif /* UNIV_DEBUG */
331 /** Updates a record when the update causes no size changes in its fields.
332  @return locking or undo log related error code, or
333  @retval DB_SUCCESS on success
334  @retval DB_ZIP_OVERFLOW if there is not enough space left
335  on the compressed page (IBUF_BITMAP_FREE was reset outside mtr) */
336 dberr_t btr_cur_update_in_place(
337     ulint flags,         /*!< in: undo logging and locking flags */
338     btr_cur_t *cursor,   /*!< in: cursor on the record to update;
339                          cursor stays valid and positioned on the
340                          same record */
341     ulint *offsets,      /*!< in/out: offsets on cursor->page_cur.rec */
342     const upd_t *update, /*!< in: update vector */
343     ulint cmpl_info,     /*!< in: compiler info on secondary index
344                        updates */
345     que_thr_t *thr,      /*!< in: query thread, or NULL if
346                          flags & (BTR_NO_LOCKING_FLAG
347                          | BTR_NO_UNDO_LOG_FLAG
348                          | BTR_CREATE_FLAG
349                          | BTR_KEEP_SYS_FLAG) */
350     trx_id_t trx_id,     /*!< in: transaction id */
351     mtr_t *mtr)          /*!< in/out: mini-transaction; if this
352                          is a secondary index, the caller must
353                          mtr_commit(mtr) before latching any
354                          further pages */
355     MY_ATTRIBUTE((warn_unused_result));
356 /** Writes a redo log record of updating a record in-place. */
357 void btr_cur_update_in_place_log(
358     ulint flags,         /*!< in: undo logging and locking flags */
359     const rec_t *rec,    /*!< in: record */
360     dict_index_t *index, /*!< in: index of the record */
361     const upd_t *update, /*!< in: update vector */
362     trx_id_t trx_id,     /*!< in: transaction id */
363     roll_ptr_t roll_ptr, /*!< in: roll ptr */
364     mtr_t *mtr);         /*!< in: mtr */
365 /** Tries to update a record on a page in an index tree. It is assumed that mtr
366  holds an x-latch on the page. The operation does not succeed if there is too
367  little space on the page or if the update would result in too empty a page,
368  so that tree compression is recommended.
369  @return error code, including
370  @retval DB_SUCCESS on success
371  @retval DB_OVERFLOW if the updated record does not fit
372  @retval DB_UNDERFLOW if the page would become too empty
373  @retval DB_ZIP_OVERFLOW if there is not enough space left
374  on the compressed page */
375 dberr_t btr_cur_optimistic_update(
376     ulint flags,         /*!< in: undo logging and locking flags */
377     btr_cur_t *cursor,   /*!< in: cursor on the record to update;
378                          cursor stays valid and positioned on the
379                          same record */
380     ulint **offsets,     /*!< out: offsets on cursor->page_cur.rec */
381     mem_heap_t **heap,   /*!< in/out: pointer to NULL or memory heap */
382     const upd_t *update, /*!< in: update vector; this must also
383                          contain trx id and roll ptr fields */
384     ulint cmpl_info,     /*!< in: compiler info on secondary index
385                        updates */
386     que_thr_t *thr,      /*!< in: query thread, or NULL if
387                          flags & (BTR_NO_UNDO_LOG_FLAG
388                          | BTR_NO_LOCKING_FLAG
389                          | BTR_CREATE_FLAG
390                          | BTR_KEEP_SYS_FLAG) */
391     trx_id_t trx_id,     /*!< in: transaction id */
392     mtr_t *mtr)          /*!< in/out: mini-transaction; if this
393                          is a secondary index, the caller must
394                          mtr_commit(mtr) before latching any
395                          further pages */
396     MY_ATTRIBUTE((warn_unused_result));
397 
398 /** Performs an update of a record on a page of a tree. It is assumed
399 that mtr holds an x-latch on the tree and on the cursor page. If the
400 update is made on the leaf level, to avoid deadlocks, mtr must also
401 own x-latches to brothers of page, if those brothers exist.
402 @param[in]     flags         undo logging, locking, and rollback flags
403 @param[in,out] cursor        cursor on the record to update;
404                              cursor may become invalid if *big_rec == NULL
405                              || !(flags & BTR_KEEP_POS_FLAG)
406 @param[out]    offsets       offsets on cursor->page_cur.rec
407 @param[in,out] offsets_heap  pointer to memory heap that can be emptied,
408                              or NULL
409 @param[in,out] entry_heap    memory heap for allocating big_rec and the
410                              index tuple.
411 @param[out]    big_rec       big rec vector whose fields have to be stored
412                              externally by the caller, or NULL
413 @param[in,out] update        update vector; this is allowed to also contain
414                              trx id and roll ptr fields. Non-updated columns
415                              that are moved offpage will be appended to this.
416 @param[in]     cmpl_info     compiler info on secondary index updates
417 @param[in]     thr           query thread, or NULL if flags &
418                              (BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG |
419                               BTR_CREATE_FLAG | BTR_KEEP_SYS_FLAG)
420 @param[in]     trx_id        transaction id
421 @param[in]     undo_no       undo number of the transaction. This is needed
422                              for rollback to savepoint of partially updated LOB.
423 @param[in,out] mtr           mini transaction; must be committed before latching
424                              any further pages
425 @param[in]     pcur          the persistent cursor on the record to update.
426 @return DB_SUCCESS or error code */
427 dberr_t btr_cur_pessimistic_update(
428     ulint flags, btr_cur_t *cursor, ulint **offsets, mem_heap_t **offsets_heap,
429     mem_heap_t *entry_heap, big_rec_t **big_rec, upd_t *update, ulint cmpl_info,
430     que_thr_t *thr, trx_id_t trx_id, undo_no_t undo_no, mtr_t *mtr,
431     btr_pcur_t *pcur = nullptr) MY_ATTRIBUTE((warn_unused_result));
432 
433 /** Marks a clustered index record deleted. Writes an undo log record to
434  undo log on this delete marking. Writes in the trx id field the id
435  of the deleting transaction, and in the roll ptr field pointer to the
436  undo log record created.
437  @return DB_SUCCESS, DB_LOCK_WAIT, or error number */
438 dberr_t btr_cur_del_mark_set_clust_rec(
439     ulint flags,           /*!< in: undo logging and locking flags */
440     buf_block_t *block,    /*!< in/out: buffer block of the record */
441     rec_t *rec,            /*!< in/out: record */
442     dict_index_t *index,   /*!< in: clustered index of the record */
443     const ulint *offsets,  /*!< in: rec_get_offsets(rec) */
444     que_thr_t *thr,        /*!< in: query thread */
445     const dtuple_t *entry, /*!< in: dtuple for the deleting record */
446     mtr_t *mtr)            /*!< in/out: mini-transaction */
447     MY_ATTRIBUTE((warn_unused_result));
448 /** Sets a secondary index record delete mark to TRUE or FALSE.
449  @return DB_SUCCESS, DB_LOCK_WAIT, or error number */
450 dberr_t btr_cur_del_mark_set_sec_rec(
451     ulint flags,       /*!< in: locking flag */
452     btr_cur_t *cursor, /*!< in: cursor */
453     ibool val,         /*!< in: value to set */
454     que_thr_t *thr,    /*!< in: query thread */
455     mtr_t *mtr)        /*!< in/out: mini-transaction */
456     MY_ATTRIBUTE((warn_unused_result));
457 /** Tries to compress a page of the tree if it seems useful. It is assumed
458  that mtr holds an x-latch on the tree and on the cursor page. To avoid
459  deadlocks, mtr must also own x-latches to brothers of page, if those
460  brothers exist. NOTE: it is assumed that the caller has reserved enough
461  free extents so that the compression will always succeed if done!
462  @return true if compression occurred */
463 ibool btr_cur_compress_if_useful(
464     btr_cur_t *cursor, /*!< in/out: cursor on the page to compress;
465                        cursor does not stay valid if compression
466                        occurs */
467     ibool adjust,      /*!< in: TRUE if should adjust the
468                        cursor position even if compression occurs */
469     mtr_t *mtr);       /*!< in/out: mini-transaction */
470 /** Removes the record on which the tree cursor is positioned. It is assumed
471  that the mtr has an x-latch on the page where the cursor is positioned,
472  but no latch on the whole tree.
473  @return true if success, i.e., the page did not become too empty */
474 ibool btr_cur_optimistic_delete_func(
475     btr_cur_t *cursor, /*!< in: cursor on the record to delete;
476                        cursor stays valid: if deletion succeeds,
477                        on function exit it points to the successor
478                        of the deleted record */
479 #ifdef UNIV_DEBUG
480     ulint flags, /*!< in: BTR_CREATE_FLAG or 0 */
481 #endif           /* UNIV_DEBUG */
482     mtr_t *mtr)  /*!< in: mtr; if this function returns
483                  TRUE on a leaf page of a secondary
484                  index, the mtr must be committed
485                  before latching any further pages */
486     MY_ATTRIBUTE((warn_unused_result));
487 #ifdef UNIV_DEBUG
488 #define btr_cur_optimistic_delete(cursor, flags, mtr) \
489   btr_cur_optimistic_delete_func(cursor, flags, mtr)
490 #else /* UNIV_DEBUG */
491 #define btr_cur_optimistic_delete(cursor, flags, mtr) \
492   btr_cur_optimistic_delete_func(cursor, mtr)
493 #endif /* UNIV_DEBUG */
494 
495 /** Removes the record on which the tree cursor is positioned. Tries
496  to compress the page if its fillfactor drops below a threshold
497  or if it is the only page on the level. It is assumed that mtr holds
498  an x-latch on the tree and on the cursor page. To avoid deadlocks,
499  mtr must also own x-latches to brothers of page, if those brothers
500  exist.
501 @param[out] err DB_SUCCESS or DB_OUT_OF_FILE_SPACE; the latter may occur
502                 because we may have to update node pointers on upper
503                 levels, and in the case of variable length keys these may
504                 actually grow in size
505 @param[in] has_reserved_extents TRUE if the caller has already reserved
506                                 enough free extents so that he knows
507                                 that the operation will succeed
508 @param[in] cursor cursor on the record to delete; if compression does not
509                   occur, the cursor stays valid: it points to successor of
510                   deleted record on function exit
511 @param[in] flags  BTR_CREATE_FLAG or 0
512 @param[in] rollback true if performing rollback, false otherwise.
513 @param[in] trx_id the current transaction id.
514 @param[in] undo_no undo number of the transaction. This is needed for rollback
515                    to savepoint of partially updated LOB.
516 @param[in] rec_type undo record type.
517 @param[in] mtr the mini transaction
518 @param[in] pcur   persistent cursor on the record to delete.
519 @return true if compression occurred */
520 ibool btr_cur_pessimistic_delete(dberr_t *err, ibool has_reserved_extents,
521                                  btr_cur_t *cursor, uint32_t flags,
522                                  bool rollback, trx_id_t trx_id,
523                                  undo_no_t undo_no, ulint rec_type, mtr_t *mtr,
524                                  btr_pcur_t *pcur = nullptr);
525 
526 /** Parses a redo log record of updating a record in-place.
527  @return end of log record or NULL */
528 byte *btr_cur_parse_update_in_place(
529     byte *ptr,                /*!< in: buffer */
530     byte *end_ptr,            /*!< in: buffer end */
531     page_t *page,             /*!< in/out: page or NULL */
532     page_zip_des_t *page_zip, /*!< in/out: compressed page, or NULL */
533     dict_index_t *index);     /*!< in: index corresponding to page */
534 /** Parses the redo log record for delete marking or unmarking of a clustered
535  index record.
536  @return end of log record or NULL */
537 byte *btr_cur_parse_del_mark_set_clust_rec(
538     byte *ptr,                /*!< in: buffer */
539     byte *end_ptr,            /*!< in: buffer end */
540     page_t *page,             /*!< in/out: page or NULL */
541     page_zip_des_t *page_zip, /*!< in/out: compressed page, or NULL */
542     dict_index_t *index);     /*!< in: index corresponding to page */
543 /** Parses the redo log record for delete marking or unmarking of a secondary
544  index record.
545  @return end of log record or NULL */
546 byte *btr_cur_parse_del_mark_set_sec_rec(
547     byte *ptr,                 /*!< in: buffer */
548     byte *end_ptr,             /*!< in: buffer end */
549     page_t *page,              /*!< in/out: page or NULL */
550     page_zip_des_t *page_zip); /*!< in/out: compressed page, or NULL */
551 #ifndef UNIV_HOTBACKUP
552 
553 /** Estimates the number of rows in a given index range.
554 @param[in]	index	index
555 @param[in]	tuple1	range start, may also be empty tuple
556 @param[in]	mode1	search mode for range start
557 @param[in]	tuple2	range end, may also be empty tuple
558 @param[in]	mode2	search mode for range end
559 @return estimated number of rows */
560 int64_t btr_estimate_n_rows_in_range(dict_index_t *index,
561                                      const dtuple_t *tuple1,
562                                      page_cur_mode_t mode1,
563                                      const dtuple_t *tuple2,
564                                      page_cur_mode_t mode2);
565 
566 /** Estimates the number of different key values in a given index, for
567  each n-column prefix of the index where 1 <= n <=
568  dict_index_get_n_unique(index). The estimates are stored in the array
569  index->stat_n_diff_key_vals[] (indexed 0..n_uniq-1) and the number of pages
570  that were sampled is saved in index->stat_n_sample_sizes[]. If
571  innodb_stats_method is nulls_ignored, we also record the number of non-null
572  values for each prefix and stored the estimates in array
573  index->stat_n_non_null_key_vals.
574  @return true if the index is available and we get the estimated numbers,
575  false if the index is unavailable. */
576 bool btr_estimate_number_of_different_key_vals(
577     dict_index_t *index); /*!< in: index */
578 
579 /** Copies an externally stored field of a record to mem heap.
580 @param[in]	trx		the trx doing the operation.
581 @param[in]	index		index containing the LOB.
582 @param[in]	rec		record in a clustered index; must be
583                                 protected by a lock or a page latch
584 @param[in]	offsets		array returned by rec_get_offsets()
585 @param[in]	page_size	BLOB page size
586 @param[in]	no		field number
587 @param[out]	len		length of the field
588 @param[out]	lob_version	version of lob */
589 #ifdef UNIV_DEBUG
590 /**
591 @param[in]	is_sdi		true for SDI Indexes */
592 #endif /* UNIV_DEBUG */
593 /**
594 @param[in,out]	heap		mem heap
595 @return the field copied to heap, or NULL if the field is incomplete */
596 byte *btr_rec_copy_externally_stored_field_func(
597     trx_t *trx, dict_index_t *index, const rec_t *rec, const ulint *offsets,
598     const page_size_t &page_size, ulint no, ulint *len, size_t *lob_version,
599 #ifdef UNIV_DEBUG
600     bool is_sdi,
601 #endif /* UNIV_DEBUG */
602     mem_heap_t *heap);
603 
604 /** Sets a secondary index record's delete mark to the given value. This
605  function is only used by the insert buffer merge mechanism. */
606 void btr_cur_set_deleted_flag_for_ibuf(
607     rec_t *rec,               /*!< in/out: record */
608     page_zip_des_t *page_zip, /*!< in/out: compressed page
609                               corresponding to rec, or NULL
610                               when the tablespace is uncompressed */
611     ibool val,                /*!< in: value to set */
612     mtr_t *mtr);              /*!< in/out: mini-transaction */
613 
614 /** The following function is used to set the deleted bit of a record.
615 @param[in,out]	rec		physical record
616 @param[in,out]	page_zip	compressed page (or NULL)
617 @param[in]	flag		nonzero if delete marked */
618 UNIV_INLINE
619 void btr_rec_set_deleted_flag(rec_t *rec, page_zip_des_t *page_zip, ulint flag);
620 
621 /** Latches the leaf page or pages requested.
622 @param[in]	block		leaf page where the search converged
623 @param[in]	page_id		page id of the leaf
624 @param[in]	latch_mode	BTR_SEARCH_LEAF, ...
625 @param[in]	cursor		cursor
626 @param[in]	mtr		mini-transaction
627 @return	blocks and savepoints which actually latched. */
628 btr_latch_leaves_t btr_cur_latch_leaves(buf_block_t *block,
629                                         const page_id_t &page_id,
630                                         const page_size_t &page_size,
631                                         ulint latch_mode, btr_cur_t *cursor,
632                                         mtr_t *mtr);
633 #endif /* !UNIV_HOTBACKUP */
634 
635 /*######################################################################*/
636 
637 /** In the pessimistic delete, if the page data size drops below this
638 limit, merging it to a neighbor is tried */
639 #define BTR_CUR_PAGE_COMPRESS_LIMIT(index) \
640   ((UNIV_PAGE_SIZE * (ulint)((index)->merge_threshold)) / 100)
641 
642 /** A slot in the path array. We store here info on a search path down the
643 tree. Each slot contains data on a single level of the tree. */
644 struct btr_path_t {
645   /* Assume a page like:
646   records:		(inf, a, b, c, d, sup)
647   index of the record:	0, 1, 2, 3, 4, 5
648   */
649 
650   /** Index of the record where the page cursor stopped on this level
651   (index in alphabetical order). Value ULINT_UNDEFINED denotes array
652   end. In the above example, if the search stopped on record 'c', then
653   nth_rec will be 3. */
654   ulint nth_rec{ULINT_UNDEFINED};
655 
656   /** Number of the records on the page, not counting inf and sup.
657   In the above example n_recs will be 4. */
658   ulint n_recs{ULINT_UNDEFINED};
659 
660   /** Number of the page containing the record. */
661   page_no_t page_no{FIL_NULL};
662 
663   /** Level of the page. If later we fetch the page under page_no
664   and it is on a different level then we know that the tree has been
665   reorganized. */
666   ulint page_level{ULINT_UNDEFINED};
667 };
668 
669 #define BTR_PATH_ARRAY_N_SLOTS 250 /*!< size of path array (in slots) */
670 
671 /** Values for the flag documenting the used search method */
672 enum btr_cur_method {
673   BTR_CUR_UNSET = 0,      /*!< Flag for initialization only,
674                           not in real use. */
675   BTR_CUR_HASH = 1,       /*!< successful shortcut using
676                           the hash index */
677   BTR_CUR_HASH_FAIL,      /*!< failure using hash, success using
678                           binary search: the misleading hash
679                           reference is stored in the field
680                           hash_node, and might be necessary to
681                           update */
682   BTR_CUR_BINARY,         /*!< success using the binary search */
683   BTR_CUR_INSERT_TO_IBUF, /*!< performed the intended insert to
684                           the insert buffer */
685   BTR_CUR_DEL_MARK_IBUF,  /*!< performed the intended delete
686                           mark in the insert/delete buffer */
687   BTR_CUR_DELETE_IBUF,    /*!< performed the intended delete in
688                           the insert/delete buffer */
689   BTR_CUR_DELETE_REF      /*!< row_purge_poss_sec() failed */
690 };
691 
692 /** The tree cursor: the definition appears here only for the compiler
693 to know struct size! */
694 struct btr_cur_t {
695   dict_index_t *index{nullptr};      /*!< index where positioned */
696   page_cur_t page_cur;               /*!< page cursor */
697   purge_node_t *purge_node{nullptr}; /*!< purge node, for BTR_DELETE */
698   buf_block_t *left_block{nullptr};  /*!< this field is used to store
699                              a pointer to the left neighbor
700                              page, in the cases
701                              BTR_SEARCH_PREV and
702                              BTR_MODIFY_PREV */
703   /*------------------------------*/
704   que_thr_t *thr{nullptr}; /*!< this field is only used
705                            when btr_cur_search_to_nth_level
706                            is called for an index entry
707                            insertion: the calling query
708                            thread is passed here to be
709                            used in the insert buffer */
710   /*------------------------------*/
711   /** The following fields are used in
712   btr_cur_search_to_nth_level to pass information: */
713   /* @{ */
714   btr_cur_method flag{BTR_CUR_UNSET}; /*!< Search method used */
715   ulint tree_height{0};               /*!< Tree height if the search is done
716                                       for a pessimistic insert or update
717                                       operation */
718   ulint up_match{0};                  /*!< If the search mode was PAGE_CUR_LE,
719                                       the number of matched fields to the
720                                       the first user record to the right of
721                                       the cursor record after
722                                       btr_cur_search_to_nth_level;
723                                       for the mode PAGE_CUR_GE, the matched
724                                       fields to the first user record AT THE
725                                       CURSOR or to the right of it;
726                                       NOTE that the up_match and low_match
727                                       values may exceed the correct values
728                                       for comparison to the adjacent user
729                                       record if that record is on a
730                                       different leaf page! (See the note in
731                                       row_ins_duplicate_error_in_clust.) */
732   ulint up_bytes{0};                  /*!< number of matched bytes to the
733                                       right at the time cursor positioned;
734                                       only used internally in searches: not
735                                       defined after the search */
736   ulint low_match{0};                 /*!< if search mode was PAGE_CUR_LE,
737                                       the number of matched fields to the
738                                       first user record AT THE CURSOR or
739                                       to the left of it after
740                                       btr_cur_search_to_nth_level;
741                                       NOT defined for PAGE_CUR_GE or any
742                                       other search modes; see also the NOTE
743                                       in up_match! */
744   ulint low_bytes{0};                 /*!< number of matched bytes to the
745                                       left at the time cursor positioned;
746                                       only used internally in searches: not
747                                       defined after the search */
748   ulint n_fields{0};                  /*!< prefix length used in a hash
749                                       search if hash_node != NULL */
750   ulint n_bytes{0};                   /*!< hash prefix bytes if hash_node !=
751                                       NULL */
752   ulint fold{0};                      /*!< fold value used in the search if
753                                       flag is BTR_CUR_HASH */
754   /* @} */
755   btr_path_t *path_arr{nullptr}; /*!< in estimating the number of
756                          rows in range, we store in this array
757                          information of the path through
758                          the tree */
759   rtr_info_t *rtr_info{nullptr}; /*!< rtree search info */
760 
761   /** Ownership of the above rtr_info member. */
762   bool m_own_rtr_info = true;
763 
764   /** If cursor is used in a scan or simple page fetch. */
765   Page_fetch m_fetch_mode{Page_fetch::NORMAL};
766 };
767 
768 /** The following function is used to set the deleted bit of a record.
769 @param[in,out]	rec		physical record
770 @param[in,out]	page_zip	compressed page (or NULL)
771 @param[in]	flag		nonzero if delete marked */
772 UNIV_INLINE
773 void btr_rec_set_deleted_flag(rec_t *rec, page_zip_des_t *page_zip, ulint flag);
774 
775 /** If pessimistic delete fails because of lack of file space, there
776 is still a good change of success a little later.  Try this many
777 times. */
778 #define BTR_CUR_RETRY_DELETE_N_TIMES 100
779 /** If pessimistic delete fails because of lack of file space, there
780 is still a good change of success a little later.  Sleep this many
781 microseconds between retries. */
782 #define BTR_CUR_RETRY_SLEEP_TIME 50000
783 
784 /** Number of searches down the B-tree in btr_cur_search_to_nth_level(). */
785 extern ulint btr_cur_n_non_sea;
786 /** Number of successful adaptive hash index lookups in
787 btr_cur_search_to_nth_level(). */
788 extern ulint btr_cur_n_sea;
789 /** Old value of btr_cur_n_non_sea.  Copied by
790 srv_refresh_innodb_monitor_stats().  Referenced by
791 srv_printf_innodb_monitor(). */
792 extern ulint btr_cur_n_non_sea_old;
793 /** Old value of btr_cur_n_sea.  Copied by
794 srv_refresh_innodb_monitor_stats().  Referenced by
795 srv_printf_innodb_monitor(). */
796 extern ulint btr_cur_n_sea_old;
797 
798 #ifdef UNIV_DEBUG
799 /* Flag to limit optimistic insert records */
800 extern uint btr_cur_limit_optimistic_insert_debug;
801 #endif /* UNIV_DEBUG */
802 
803 #include "btr0cur.ic"
804 
805 #endif
806