2014-02-26 19:11:54 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
|
2016-06-21 14:21:03 +02:00
|
|
|
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
2017-03-01 08:27:39 +02:00
|
|
|
Copyright (c) 2017, MariaDB Corporation.
|
2014-02-26 19:11:54 +01:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU General Public License as published by the Free Software
|
|
|
|
Foundation; version 2 of the License.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
|
|
this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
|
|
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
/**************************************************//**
|
|
|
|
@file include/btr0pcur.h
|
|
|
|
The index tree persistent cursor
|
|
|
|
|
|
|
|
Created 2/23/1996 Heikki Tuuri
|
|
|
|
*******************************************************/
|
|
|
|
|
|
|
|
#ifndef btr0pcur_h
|
|
|
|
#define btr0pcur_h
|
|
|
|
|
|
|
|
#include "univ.i"
|
|
|
|
#include "dict0dict.h"
|
|
|
|
#include "data0data.h"
|
|
|
|
#include "mtr0mtr.h"
|
|
|
|
#include "page0cur.h"
|
|
|
|
#include "btr0cur.h"
|
|
|
|
#include "btr0btr.h"
|
|
|
|
#include "btr0types.h"
|
2016-08-12 11:17:45 +03:00
|
|
|
#include "gis0rtree.h"
|
2014-02-26 19:11:54 +01:00
|
|
|
|
|
|
|
/* Relative positions for a stored cursor position */
|
2016-08-12 11:17:45 +03:00
|
|
|
enum btr_pcur_pos_t {
|
|
|
|
BTR_PCUR_ON = 1,
|
|
|
|
BTR_PCUR_BEFORE = 2,
|
|
|
|
BTR_PCUR_AFTER = 3,
|
2014-02-26 19:11:54 +01:00
|
|
|
/* Note that if the tree is not empty, btr_pcur_store_position does not
|
|
|
|
use the following, but only uses the above three alternatives, where the
|
|
|
|
position is stored relative to a specific record: this makes implementation
|
|
|
|
of a scroll cursor easier */
|
2016-08-12 11:17:45 +03:00
|
|
|
BTR_PCUR_BEFORE_FIRST_IN_TREE = 4, /* in an empty tree */
|
|
|
|
BTR_PCUR_AFTER_LAST_IN_TREE = 5 /* in an empty tree */
|
|
|
|
};
|
2014-02-26 19:11:54 +01:00
|
|
|
|
|
|
|
/**************************************************************//**
|
|
|
|
Allocates memory for a persistent cursor object and initializes the cursor.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return own: persistent cursor */
|
2014-02-26 19:11:54 +01:00
|
|
|
btr_pcur_t*
|
|
|
|
btr_pcur_create_for_mysql(void);
|
|
|
|
/*============================*/
|
|
|
|
|
|
|
|
/**************************************************************//**
|
|
|
|
Resets a persistent cursor object, freeing ::old_rec_buf if it is
|
|
|
|
allocated and resetting the other members to their initial values. */
|
|
|
|
void
|
|
|
|
btr_pcur_reset(
|
|
|
|
/*===========*/
|
|
|
|
btr_pcur_t* cursor);/*!< in, out: persistent cursor */
|
|
|
|
|
|
|
|
/**************************************************************//**
|
|
|
|
Frees the memory for a persistent cursor object. */
|
|
|
|
void
|
|
|
|
btr_pcur_free_for_mysql(
|
|
|
|
/*====================*/
|
|
|
|
btr_pcur_t* cursor); /*!< in, own: persistent cursor */
|
|
|
|
/**************************************************************//**
|
|
|
|
Copies the stored position of a pcur to another pcur. */
|
|
|
|
void
|
|
|
|
btr_pcur_copy_stored_position(
|
|
|
|
/*==========================*/
|
|
|
|
btr_pcur_t* pcur_receive, /*!< in: pcur which will receive the
|
|
|
|
position info */
|
|
|
|
btr_pcur_t* pcur_donate); /*!< in: pcur from which the info is
|
|
|
|
copied */
|
|
|
|
/**************************************************************//**
|
|
|
|
Sets the old_rec_buf field to NULL. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
btr_pcur_init(
|
|
|
|
/*==========*/
|
|
|
|
btr_pcur_t* pcur); /*!< in: persistent cursor */
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
/** Free old_rec_buf.
|
|
|
|
@param[in] pcur Persistent cursor holding old_rec to be freed. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
btr_pcur_free(
|
|
|
|
btr_pcur_t* pcur);
|
|
|
|
|
2014-02-26 19:11:54 +01:00
|
|
|
/**************************************************************//**
|
|
|
|
Initializes and opens a persistent cursor to an index tree. It should be
|
|
|
|
closed with btr_pcur_close. */
|
|
|
|
UNIV_INLINE
|
2017-05-05 10:25:29 +03:00
|
|
|
dberr_t
|
2014-02-26 19:11:54 +01:00
|
|
|
btr_pcur_open_low(
|
|
|
|
/*==============*/
|
|
|
|
dict_index_t* index, /*!< in: index */
|
|
|
|
ulint level, /*!< in: level in the btree */
|
|
|
|
const dtuple_t* tuple, /*!< in: tuple on which search done */
|
2016-08-12 11:17:45 +03:00
|
|
|
page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ...;
|
2014-02-26 19:11:54 +01:00
|
|
|
NOTE that if the search is made using a unique
|
|
|
|
prefix of a record, mode should be
|
|
|
|
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
|
|
|
|
may end up on the previous page from the
|
|
|
|
record! */
|
|
|
|
ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
|
|
|
|
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
|
|
|
|
const char* file, /*!< in: file name */
|
2017-03-01 08:27:39 +02:00
|
|
|
unsigned line, /*!< in: line where called */
|
MDEV-6076 Persistent AUTO_INCREMENT for InnoDB
This should be functionally equivalent to WL#6204 in MySQL 8.0.0, with
the notable difference that the file format changes are limited to
repurposing a previously unused data field in B-tree pages.
For persistent InnoDB tables, write the last used AUTO_INCREMENT
value to the root page of the clustered index, in the previously
unused (0) PAGE_MAX_TRX_ID field, now aliased as PAGE_ROOT_AUTO_INC.
Unlike some other previously unused InnoDB data fields, this one was
actually always zero-initialized, at least since MySQL 3.23.49.
The writes to PAGE_ROOT_AUTO_INC are protected by SX or X latch on the
root page. The SX latch will allow concurrent read access to the root
page. (The field PAGE_ROOT_AUTO_INC will only be read on the
first-time call to ha_innobase::open() from the SQL layer. The
PAGE_ROOT_AUTO_INC can only be updated when executing SQL, so
read/write races are not possible.)
During INSERT, the PAGE_ROOT_AUTO_INC is updated by the low-level
function btr_cur_search_to_nth_level(), adding no extra page
access. [Adaptive hash index lookup will be disabled during INSERT.]
If some rare UPDATE modifies an AUTO_INCREMENT column, the
PAGE_ROOT_AUTO_INC will be adjusted in a separate mini-transaction in
ha_innobase::update_row().
When a page is reorganized, we have to preserve the PAGE_ROOT_AUTO_INC
field.
During ALTER TABLE, the initial AUTO_INCREMENT value will be copied
from the table. ALGORITHM=COPY and online log apply in LOCK=NONE will
update PAGE_ROOT_AUTO_INC in real time.
innodb_col_no(): Determine the dict_table_t::cols[] element index
corresponding to a Field of a non-virtual column.
(The MySQL 5.7 implementation of virtual columns breaks the 1:1
relationship between Field::field_index and dict_table_t::cols[].
Virtual columns are omitted from dict_table_t::cols[]. Therefore,
we must translate the field_index of AUTO_INCREMENT columns into
an index of dict_table_t::cols[].)
Upgrade from old data files:
By default, the AUTO_INCREMENT sequence in old data files would appear
to be reset, because PAGE_MAX_TRX_ID or PAGE_ROOT_AUTO_INC would contain
the value 0 in each clustered index page. In new data files,
PAGE_ROOT_AUTO_INC can only be 0 if the table is empty or does not contain
any AUTO_INCREMENT column.
For backward compatibility, we use the old method of
SELECT MAX(auto_increment_column) for initializing the sequence.
btr_read_autoinc(): Read the AUTO_INCREMENT sequence from a new-format
data file.
btr_read_autoinc_with_fallback(): A variant of btr_read_autoinc()
that will resort to reading MAX(auto_increment_column) for data files
that did not use AUTO_INCREMENT yet. It was manually tested that during
the execution of innodb.autoinc_persist the compatibility logic is
not activated (for new files, PAGE_ROOT_AUTO_INC is never 0 in nonempty
clustered index root pages).
initialize_auto_increment(): Replaces
ha_innobase::innobase_initialize_autoinc(). This initializes
the AUTO_INCREMENT metadata. Only called from ha_innobase::open().
ha_innobase::info_low(): Do not try to lazily initialize
dict_table_t::autoinc. It must already have been initialized by
ha_innobase::open() or ha_innobase::create().
Note: The adjustments to class ha_innopart were not tested, because
the source code (native InnoDB partitioning) is not being compiled.
2016-12-14 19:56:39 +02:00
|
|
|
ib_uint64_t autoinc,/*!< in: PAGE_ROOT_AUTO_INC to be written
|
|
|
|
(0 if none) */
|
2014-02-26 19:11:54 +01:00
|
|
|
mtr_t* mtr); /*!< in: mtr */
|
|
|
|
#define btr_pcur_open(i,t,md,l,c,m) \
|
MDEV-6076 Persistent AUTO_INCREMENT for InnoDB
This should be functionally equivalent to WL#6204 in MySQL 8.0.0, with
the notable difference that the file format changes are limited to
repurposing a previously unused data field in B-tree pages.
For persistent InnoDB tables, write the last used AUTO_INCREMENT
value to the root page of the clustered index, in the previously
unused (0) PAGE_MAX_TRX_ID field, now aliased as PAGE_ROOT_AUTO_INC.
Unlike some other previously unused InnoDB data fields, this one was
actually always zero-initialized, at least since MySQL 3.23.49.
The writes to PAGE_ROOT_AUTO_INC are protected by SX or X latch on the
root page. The SX latch will allow concurrent read access to the root
page. (The field PAGE_ROOT_AUTO_INC will only be read on the
first-time call to ha_innobase::open() from the SQL layer. The
PAGE_ROOT_AUTO_INC can only be updated when executing SQL, so
read/write races are not possible.)
During INSERT, the PAGE_ROOT_AUTO_INC is updated by the low-level
function btr_cur_search_to_nth_level(), adding no extra page
access. [Adaptive hash index lookup will be disabled during INSERT.]
If some rare UPDATE modifies an AUTO_INCREMENT column, the
PAGE_ROOT_AUTO_INC will be adjusted in a separate mini-transaction in
ha_innobase::update_row().
When a page is reorganized, we have to preserve the PAGE_ROOT_AUTO_INC
field.
During ALTER TABLE, the initial AUTO_INCREMENT value will be copied
from the table. ALGORITHM=COPY and online log apply in LOCK=NONE will
update PAGE_ROOT_AUTO_INC in real time.
innodb_col_no(): Determine the dict_table_t::cols[] element index
corresponding to a Field of a non-virtual column.
(The MySQL 5.7 implementation of virtual columns breaks the 1:1
relationship between Field::field_index and dict_table_t::cols[].
Virtual columns are omitted from dict_table_t::cols[]. Therefore,
we must translate the field_index of AUTO_INCREMENT columns into
an index of dict_table_t::cols[].)
Upgrade from old data files:
By default, the AUTO_INCREMENT sequence in old data files would appear
to be reset, because PAGE_MAX_TRX_ID or PAGE_ROOT_AUTO_INC would contain
the value 0 in each clustered index page. In new data files,
PAGE_ROOT_AUTO_INC can only be 0 if the table is empty or does not contain
any AUTO_INCREMENT column.
For backward compatibility, we use the old method of
SELECT MAX(auto_increment_column) for initializing the sequence.
btr_read_autoinc(): Read the AUTO_INCREMENT sequence from a new-format
data file.
btr_read_autoinc_with_fallback(): A variant of btr_read_autoinc()
that will resort to reading MAX(auto_increment_column) for data files
that did not use AUTO_INCREMENT yet. It was manually tested that during
the execution of innodb.autoinc_persist the compatibility logic is
not activated (for new files, PAGE_ROOT_AUTO_INC is never 0 in nonempty
clustered index root pages).
initialize_auto_increment(): Replaces
ha_innobase::innobase_initialize_autoinc(). This initializes
the AUTO_INCREMENT metadata. Only called from ha_innobase::open().
ha_innobase::info_low(): Do not try to lazily initialize
dict_table_t::autoinc. It must already have been initialized by
ha_innobase::open() or ha_innobase::create().
Note: The adjustments to class ha_innopart were not tested, because
the source code (native InnoDB partitioning) is not being compiled.
2016-12-14 19:56:39 +02:00
|
|
|
btr_pcur_open_low(i,0,t,md,l,c,__FILE__,__LINE__,0,m)
|
2014-02-26 19:11:54 +01:00
|
|
|
/**************************************************************//**
|
|
|
|
Opens an persistent cursor to an index tree without initializing the
|
|
|
|
cursor. */
|
|
|
|
UNIV_INLINE
|
2015-08-31 19:47:14 +03:00
|
|
|
dberr_t
|
2014-02-26 19:11:54 +01:00
|
|
|
btr_pcur_open_with_no_init_func(
|
|
|
|
/*============================*/
|
|
|
|
dict_index_t* index, /*!< in: index */
|
|
|
|
const dtuple_t* tuple, /*!< in: tuple on which search done */
|
2016-08-12 11:17:45 +03:00
|
|
|
page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ...;
|
2014-02-26 19:11:54 +01:00
|
|
|
NOTE that if the search is made using a unique
|
|
|
|
prefix of a record, mode should be
|
|
|
|
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
|
|
|
|
may end up on the previous page of the
|
|
|
|
record! */
|
|
|
|
ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ...;
|
|
|
|
NOTE that if has_search_latch != 0 then
|
|
|
|
we maybe do not acquire a latch on the cursor
|
|
|
|
page, but assume that the caller uses his
|
|
|
|
btr search latch to protect the record! */
|
|
|
|
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
|
2016-08-12 11:17:45 +03:00
|
|
|
ulint has_search_latch,
|
|
|
|
/*!< in: latch mode the caller
|
|
|
|
currently has on search system:
|
2014-02-26 19:11:54 +01:00
|
|
|
RW_S_LATCH, or 0 */
|
|
|
|
const char* file, /*!< in: file name */
|
2017-03-01 08:27:39 +02:00
|
|
|
unsigned line, /*!< in: line where called */
|
2014-02-26 19:11:54 +01:00
|
|
|
mtr_t* mtr); /*!< in: mtr */
|
|
|
|
#define btr_pcur_open_with_no_init(ix,t,md,l,cur,has,m) \
|
|
|
|
btr_pcur_open_with_no_init_func(ix,t,md,l,cur,has,__FILE__,__LINE__,m)
|
|
|
|
|
|
|
|
/*****************************************************************//**
|
|
|
|
Opens a persistent cursor at either end of an index. */
|
|
|
|
UNIV_INLINE
|
2015-08-31 19:47:14 +03:00
|
|
|
dberr_t
|
2014-02-26 19:11:54 +01:00
|
|
|
btr_pcur_open_at_index_side(
|
|
|
|
/*========================*/
|
|
|
|
bool from_left, /*!< in: true if open to the low end,
|
|
|
|
false if to the high end */
|
|
|
|
dict_index_t* index, /*!< in: index */
|
|
|
|
ulint latch_mode, /*!< in: latch mode */
|
|
|
|
btr_pcur_t* pcur, /*!< in/out: cursor */
|
|
|
|
bool init_pcur, /*!< in: whether to initialize pcur */
|
|
|
|
ulint level, /*!< in: level to search for
|
|
|
|
(0=leaf) */
|
|
|
|
mtr_t* mtr) /*!< in/out: mini-transaction */
|
2016-06-21 14:21:03 +02:00
|
|
|
MY_ATTRIBUTE((nonnull));
|
2014-02-26 19:11:54 +01:00
|
|
|
/**************************************************************//**
|
|
|
|
Gets the up_match value for a pcur after a search.
|
|
|
|
@return number of matched fields at the cursor or to the right if
|
|
|
|
search mode was PAGE_CUR_GE, otherwise undefined */
|
|
|
|
UNIV_INLINE
|
|
|
|
ulint
|
|
|
|
btr_pcur_get_up_match(
|
|
|
|
/*==================*/
|
|
|
|
const btr_pcur_t* cursor); /*!< in: persistent cursor */
|
|
|
|
/**************************************************************//**
|
|
|
|
Gets the low_match value for a pcur after a search.
|
|
|
|
@return number of matched fields at the cursor or to the right if
|
|
|
|
search mode was PAGE_CUR_LE, otherwise undefined */
|
|
|
|
UNIV_INLINE
|
|
|
|
ulint
|
|
|
|
btr_pcur_get_low_match(
|
|
|
|
/*===================*/
|
|
|
|
const btr_pcur_t* cursor); /*!< in: persistent cursor */
|
|
|
|
/**************************************************************//**
|
|
|
|
If mode is PAGE_CUR_G or PAGE_CUR_GE, opens a persistent cursor on the first
|
|
|
|
user record satisfying the search condition, in the case PAGE_CUR_L or
|
|
|
|
PAGE_CUR_LE, on the last user record. If no such user record exists, then
|
|
|
|
in the first case sets the cursor after last in tree, and in the latter case
|
|
|
|
before first in tree. The latching mode must be BTR_SEARCH_LEAF or
|
|
|
|
BTR_MODIFY_LEAF. */
|
|
|
|
void
|
|
|
|
btr_pcur_open_on_user_rec_func(
|
|
|
|
/*===========================*/
|
|
|
|
dict_index_t* index, /*!< in: index */
|
|
|
|
const dtuple_t* tuple, /*!< in: tuple on which search done */
|
2016-08-12 11:17:45 +03:00
|
|
|
page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ... */
|
2014-02-26 19:11:54 +01:00
|
|
|
ulint latch_mode, /*!< in: BTR_SEARCH_LEAF or
|
|
|
|
BTR_MODIFY_LEAF */
|
|
|
|
btr_pcur_t* cursor, /*!< in: memory buffer for persistent
|
|
|
|
cursor */
|
|
|
|
const char* file, /*!< in: file name */
|
2017-03-01 08:27:39 +02:00
|
|
|
unsigned line, /*!< in: line where called */
|
2014-02-26 19:11:54 +01:00
|
|
|
mtr_t* mtr); /*!< in: mtr */
|
|
|
|
#define btr_pcur_open_on_user_rec(i,t,md,l,c,m) \
|
|
|
|
btr_pcur_open_on_user_rec_func(i,t,md,l,c,__FILE__,__LINE__,m)
|
|
|
|
/**********************************************************************//**
|
2016-08-12 11:17:45 +03:00
|
|
|
Positions a cursor at a randomly chosen position within a B-tree.
|
|
|
|
@return true if the index is available and we have put the cursor, false
|
|
|
|
if the index is unavailable */
|
2014-02-26 19:11:54 +01:00
|
|
|
UNIV_INLINE
|
2016-08-12 11:17:45 +03:00
|
|
|
bool
|
2014-02-26 19:11:54 +01:00
|
|
|
btr_pcur_open_at_rnd_pos_func(
|
|
|
|
/*==========================*/
|
|
|
|
dict_index_t* index, /*!< in: index */
|
|
|
|
ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
|
|
|
|
btr_pcur_t* cursor, /*!< in/out: B-tree pcur */
|
|
|
|
const char* file, /*!< in: file name */
|
2017-03-01 08:27:39 +02:00
|
|
|
unsigned line, /*!< in: line where called */
|
2014-02-26 19:11:54 +01:00
|
|
|
mtr_t* mtr); /*!< in: mtr */
|
|
|
|
#define btr_pcur_open_at_rnd_pos(i,l,c,m) \
|
|
|
|
btr_pcur_open_at_rnd_pos_func(i,l,c,__FILE__,__LINE__,m)
|
|
|
|
/**************************************************************//**
|
|
|
|
Frees the possible memory heap of a persistent cursor and sets the latch
|
|
|
|
mode of the persistent cursor to BTR_NO_LATCHES.
|
|
|
|
WARNING: this function does not release the latch on the page where the
|
|
|
|
cursor is currently positioned. The latch is acquired by the
|
|
|
|
"move to next/previous" family of functions. Since recursive shared locks
|
|
|
|
are not allowed, you must take care (if using the cursor in S-mode) to
|
|
|
|
manually release the latch by either calling
|
|
|
|
btr_leaf_page_release(btr_pcur_get_block(&pcur), pcur.latch_mode, mtr)
|
|
|
|
or by committing the mini-transaction right after btr_pcur_close().
|
|
|
|
A subsequent attempt to crawl the same page in the same mtr would cause
|
|
|
|
an assertion failure. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
btr_pcur_close(
|
|
|
|
/*===========*/
|
|
|
|
btr_pcur_t* cursor); /*!< in: persistent cursor */
|
|
|
|
/**************************************************************//**
|
|
|
|
The position of the cursor is stored by taking an initial segment of the
|
|
|
|
record the cursor is positioned on, before, or after, and copying it to the
|
|
|
|
cursor data structure, or just setting a flag if the cursor id before the
|
|
|
|
first in an EMPTY tree, or after the last in an EMPTY tree. NOTE that the
|
|
|
|
page where the cursor is positioned must not be empty if the index tree is
|
|
|
|
not totally empty! */
|
|
|
|
void
|
|
|
|
btr_pcur_store_position(
|
|
|
|
/*====================*/
|
|
|
|
btr_pcur_t* cursor, /*!< in: persistent cursor */
|
|
|
|
mtr_t* mtr); /*!< in: mtr */
|
|
|
|
/**************************************************************//**
|
|
|
|
Restores the stored position of a persistent cursor bufferfixing the page and
|
|
|
|
obtaining the specified latches. If the cursor position was saved when the
|
|
|
|
(1) cursor was positioned on a user record: this function restores the position
|
|
|
|
to the last record LESS OR EQUAL to the stored record;
|
|
|
|
(2) cursor was positioned on a page infimum record: restores the position to
|
|
|
|
the last record LESS than the user record which was the successor of the page
|
|
|
|
infimum;
|
|
|
|
(3) cursor was positioned on the page supremum: restores to the first record
|
|
|
|
GREATER than the user record which was the predecessor of the supremum.
|
|
|
|
(4) cursor was positioned before the first or after the last in an empty tree:
|
|
|
|
restores to before first or after the last in the tree.
|
|
|
|
@return TRUE if the cursor position was stored when it was on a user
|
|
|
|
record and it can be restored on a user record whose ordering fields
|
|
|
|
are identical to the ones of the original user record */
|
|
|
|
ibool
|
|
|
|
btr_pcur_restore_position_func(
|
|
|
|
/*===========================*/
|
|
|
|
ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
|
|
|
|
btr_pcur_t* cursor, /*!< in: detached persistent cursor */
|
|
|
|
const char* file, /*!< in: file name */
|
2017-03-01 08:27:39 +02:00
|
|
|
unsigned line, /*!< in: line where called */
|
2014-02-26 19:11:54 +01:00
|
|
|
mtr_t* mtr); /*!< in: mtr */
|
|
|
|
#define btr_pcur_restore_position(l,cur,mtr) \
|
|
|
|
btr_pcur_restore_position_func(l,cur,__FILE__,__LINE__,mtr)
|
|
|
|
/*********************************************************//**
|
|
|
|
Gets the rel_pos field for a cursor whose position has been stored.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return BTR_PCUR_ON, ... */
|
2014-02-26 19:11:54 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
ulint
|
|
|
|
btr_pcur_get_rel_pos(
|
|
|
|
/*=================*/
|
|
|
|
const btr_pcur_t* cursor);/*!< in: persistent cursor */
|
|
|
|
/**************************************************************//**
|
|
|
|
Commits the mtr and sets the pcur latch mode to BTR_NO_LATCHES,
|
|
|
|
that is, the cursor becomes detached.
|
|
|
|
Function btr_pcur_store_position should be used before calling this,
|
|
|
|
if restoration of cursor is wanted later. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
btr_pcur_commit_specify_mtr(
|
|
|
|
/*========================*/
|
|
|
|
btr_pcur_t* pcur, /*!< in: persistent cursor */
|
|
|
|
mtr_t* mtr); /*!< in: mtr to commit */
|
|
|
|
/*********************************************************//**
|
|
|
|
Moves the persistent cursor to the next record in the tree. If no records are
|
|
|
|
left, the cursor stays 'after last in tree'.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return TRUE if the cursor was not after last in tree */
|
2014-02-26 19:11:54 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
ibool
|
|
|
|
btr_pcur_move_to_next(
|
|
|
|
/*==================*/
|
|
|
|
btr_pcur_t* cursor, /*!< in: persistent cursor; NOTE that the
|
|
|
|
function may release the page latch */
|
|
|
|
mtr_t* mtr); /*!< in: mtr */
|
|
|
|
/*********************************************************//**
|
|
|
|
Moves the persistent cursor to the previous record in the tree. If no records
|
|
|
|
are left, the cursor stays 'before first in tree'.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return TRUE if the cursor was not before first in tree */
|
2014-02-26 19:11:54 +01:00
|
|
|
ibool
|
|
|
|
btr_pcur_move_to_prev(
|
|
|
|
/*==================*/
|
|
|
|
btr_pcur_t* cursor, /*!< in: persistent cursor; NOTE that the
|
|
|
|
function may release the page latch */
|
|
|
|
mtr_t* mtr); /*!< in: mtr */
|
|
|
|
/*********************************************************//**
|
|
|
|
Moves the persistent cursor to the last record on the same page. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
btr_pcur_move_to_last_on_page(
|
|
|
|
/*==========================*/
|
|
|
|
btr_pcur_t* cursor, /*!< in: persistent cursor */
|
|
|
|
mtr_t* mtr); /*!< in: mtr */
|
|
|
|
/*********************************************************//**
|
|
|
|
Moves the persistent cursor to the next user record in the tree. If no user
|
|
|
|
records are left, the cursor ends up 'after last in tree'.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return TRUE if the cursor moved forward, ending on a user record */
|
2014-02-26 19:11:54 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
ibool
|
|
|
|
btr_pcur_move_to_next_user_rec(
|
|
|
|
/*===========================*/
|
|
|
|
btr_pcur_t* cursor, /*!< in: persistent cursor; NOTE that the
|
|
|
|
function may release the page latch */
|
|
|
|
mtr_t* mtr); /*!< in: mtr */
|
|
|
|
/*********************************************************//**
|
|
|
|
Moves the persistent cursor to the first record on the next page.
|
|
|
|
Releases the latch on the current page, and bufferunfixes it.
|
|
|
|
Note that there must not be modifications on the current page,
|
|
|
|
as then the x-latch can be released only in mtr_commit. */
|
|
|
|
void
|
|
|
|
btr_pcur_move_to_next_page(
|
|
|
|
/*=======================*/
|
|
|
|
btr_pcur_t* cursor, /*!< in: persistent cursor; must be on the
|
|
|
|
last record of the current page */
|
|
|
|
mtr_t* mtr); /*!< in: mtr */
|
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
/*********************************************************//**
|
|
|
|
Returns the btr cursor component of a persistent cursor.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return pointer to btr cursor component */
|
2014-02-26 19:11:54 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
btr_cur_t*
|
|
|
|
btr_pcur_get_btr_cur(
|
|
|
|
/*=================*/
|
|
|
|
const btr_pcur_t* cursor); /*!< in: persistent cursor */
|
|
|
|
/*********************************************************//**
|
|
|
|
Returns the page cursor component of a persistent cursor.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return pointer to page cursor component */
|
2014-02-26 19:11:54 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
page_cur_t*
|
|
|
|
btr_pcur_get_page_cur(
|
|
|
|
/*==================*/
|
|
|
|
const btr_pcur_t* cursor); /*!< in: persistent cursor */
|
|
|
|
/*********************************************************//**
|
|
|
|
Returns the page of a persistent cursor.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return pointer to the page */
|
2014-02-26 19:11:54 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
page_t*
|
|
|
|
btr_pcur_get_page(
|
|
|
|
/*==============*/
|
|
|
|
const btr_pcur_t* cursor);/*!< in: persistent cursor */
|
|
|
|
/*********************************************************//**
|
|
|
|
Returns the buffer block of a persistent cursor.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return pointer to the block */
|
2014-02-26 19:11:54 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
buf_block_t*
|
|
|
|
btr_pcur_get_block(
|
|
|
|
/*===============*/
|
|
|
|
const btr_pcur_t* cursor);/*!< in: persistent cursor */
|
|
|
|
/*********************************************************//**
|
|
|
|
Returns the record of a persistent cursor.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return pointer to the record */
|
2014-02-26 19:11:54 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
rec_t*
|
|
|
|
btr_pcur_get_rec(
|
|
|
|
/*=============*/
|
|
|
|
const btr_pcur_t* cursor);/*!< in: persistent cursor */
|
|
|
|
#else /* UNIV_DEBUG */
|
|
|
|
# define btr_pcur_get_btr_cur(cursor) (&(cursor)->btr_cur)
|
|
|
|
# define btr_pcur_get_page_cur(cursor) (&(cursor)->btr_cur.page_cur)
|
|
|
|
# define btr_pcur_get_page(cursor) ((cursor)->btr_cur.page_cur.block->frame)
|
|
|
|
# define btr_pcur_get_block(cursor) ((cursor)->btr_cur.page_cur.block)
|
|
|
|
# define btr_pcur_get_rec(cursor) ((cursor)->btr_cur.page_cur.rec)
|
|
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
/*********************************************************//**
|
|
|
|
Checks if the persistent cursor is on a user record. */
|
|
|
|
UNIV_INLINE
|
|
|
|
ibool
|
|
|
|
btr_pcur_is_on_user_rec(
|
|
|
|
/*====================*/
|
|
|
|
const btr_pcur_t* cursor);/*!< in: persistent cursor */
|
|
|
|
/*********************************************************//**
|
|
|
|
Checks if the persistent cursor is after the last user record on
|
|
|
|
a page. */
|
|
|
|
UNIV_INLINE
|
|
|
|
ibool
|
|
|
|
btr_pcur_is_after_last_on_page(
|
|
|
|
/*===========================*/
|
|
|
|
const btr_pcur_t* cursor);/*!< in: persistent cursor */
|
|
|
|
/*********************************************************//**
|
|
|
|
Checks if the persistent cursor is before the first user record on
|
|
|
|
a page. */
|
|
|
|
UNIV_INLINE
|
|
|
|
ibool
|
|
|
|
btr_pcur_is_before_first_on_page(
|
|
|
|
/*=============================*/
|
|
|
|
const btr_pcur_t* cursor);/*!< in: persistent cursor */
|
|
|
|
/*********************************************************//**
|
|
|
|
Checks if the persistent cursor is before the first user record in
|
|
|
|
the index tree. */
|
|
|
|
UNIV_INLINE
|
|
|
|
ibool
|
|
|
|
btr_pcur_is_before_first_in_tree(
|
|
|
|
/*=============================*/
|
|
|
|
btr_pcur_t* cursor, /*!< in: persistent cursor */
|
|
|
|
mtr_t* mtr); /*!< in: mtr */
|
|
|
|
/*********************************************************//**
|
|
|
|
Checks if the persistent cursor is after the last user record in
|
|
|
|
the index tree. */
|
|
|
|
UNIV_INLINE
|
|
|
|
ibool
|
|
|
|
btr_pcur_is_after_last_in_tree(
|
|
|
|
/*===========================*/
|
|
|
|
btr_pcur_t* cursor, /*!< in: persistent cursor */
|
|
|
|
mtr_t* mtr); /*!< in: mtr */
|
|
|
|
/*********************************************************//**
|
|
|
|
Moves the persistent cursor to the next record on the same page. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
btr_pcur_move_to_next_on_page(
|
|
|
|
/*==========================*/
|
|
|
|
btr_pcur_t* cursor);/*!< in/out: persistent cursor */
|
|
|
|
/*********************************************************//**
|
|
|
|
Moves the persistent cursor to the previous record on the same page. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
btr_pcur_move_to_prev_on_page(
|
|
|
|
/*==========================*/
|
|
|
|
btr_pcur_t* cursor);/*!< in/out: persistent cursor */
|
2014-05-05 18:20:28 +02:00
|
|
|
/*********************************************************//**
|
|
|
|
Moves the persistent cursor to the infimum record on the same page. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
btr_pcur_move_before_first_on_page(
|
|
|
|
/*===============================*/
|
|
|
|
btr_pcur_t* cursor); /*!< in/out: persistent cursor */
|
2014-02-26 19:11:54 +01:00
|
|
|
|
2014-02-26 19:23:04 +01:00
|
|
|
/** Position state of persistent B-tree cursor. */
|
|
|
|
enum pcur_pos_t {
|
|
|
|
/** The persistent cursor is not positioned. */
|
|
|
|
BTR_PCUR_NOT_POSITIONED = 0,
|
|
|
|
/** The persistent cursor was previously positioned.
|
|
|
|
TODO: currently, the state can be BTR_PCUR_IS_POSITIONED,
|
|
|
|
though it really should be BTR_PCUR_WAS_POSITIONED,
|
|
|
|
because we have no obligation to commit the cursor with
|
|
|
|
mtr; similarly latch_mode may be out of date. This can
|
|
|
|
lead to problems if btr_pcur is not used the right way;
|
|
|
|
all current code should be ok. */
|
|
|
|
BTR_PCUR_WAS_POSITIONED,
|
|
|
|
/** The persistent cursor is positioned by optimistic get to the same
|
|
|
|
record as it was positioned at. Not used for rel_pos == BTR_PCUR_ON.
|
|
|
|
It may need adjustment depending on previous/current search direction
|
|
|
|
and rel_pos. */
|
|
|
|
BTR_PCUR_IS_POSITIONED_OPTIMISTIC,
|
|
|
|
/** The persistent cursor is positioned by index search.
|
|
|
|
Or optimistic get for rel_pos == BTR_PCUR_ON. */
|
|
|
|
BTR_PCUR_IS_POSITIONED
|
|
|
|
};
|
2014-02-26 19:11:54 +01:00
|
|
|
|
|
|
|
/* The persistent B-tree cursor structure. This is used mainly for SQL
|
|
|
|
selects, updates, and deletes. */
|
|
|
|
|
|
|
|
struct btr_pcur_t{
|
2016-08-12 11:17:45 +03:00
|
|
|
/** a B-tree cursor */
|
|
|
|
btr_cur_t btr_cur;
|
|
|
|
/** see TODO note below!
|
|
|
|
BTR_SEARCH_LEAF, BTR_MODIFY_LEAF, BTR_MODIFY_TREE or BTR_NO_LATCHES,
|
|
|
|
depending on the latching state of the page and tree where the cursor
|
|
|
|
is positioned; BTR_NO_LATCHES means that the cursor is not currently
|
|
|
|
positioned:
|
|
|
|
we say then that the cursor is detached; it can be restored to
|
|
|
|
attached if the old position was stored in old_rec */
|
|
|
|
ulint latch_mode;
|
|
|
|
/** true if old_rec is stored */
|
|
|
|
bool old_stored;
|
|
|
|
/** if cursor position is stored, contains an initial segment of the
|
|
|
|
latest record cursor was positioned either on, before or after */
|
|
|
|
rec_t* old_rec;
|
|
|
|
/** number of fields in old_rec */
|
|
|
|
ulint old_n_fields;
|
|
|
|
/** BTR_PCUR_ON, BTR_PCUR_BEFORE, or BTR_PCUR_AFTER, depending on
|
|
|
|
whether cursor was on, before, or after the old_rec record */
|
|
|
|
enum btr_pcur_pos_t rel_pos;
|
|
|
|
/** buffer block when the position was stored */
|
|
|
|
buf_block_t* block_when_stored;
|
|
|
|
/** the modify clock value of the buffer block when the cursor position
|
|
|
|
was stored */
|
|
|
|
ib_uint64_t modify_clock;
|
|
|
|
/** the withdraw clock value of the buffer pool when the cursor
|
|
|
|
position was stored */
|
|
|
|
ulint withdraw_clock;
|
|
|
|
/** btr_pcur_store_position() and btr_pcur_restore_position() state. */
|
|
|
|
enum pcur_pos_t pos_state;
|
|
|
|
/** PAGE_CUR_G, ... */
|
|
|
|
page_cur_mode_t search_mode;
|
|
|
|
/** the transaction, if we know it; otherwise this field is not defined;
|
|
|
|
can ONLY BE USED in error prints in fatal assertion failures! */
|
|
|
|
trx_t* trx_if_known;
|
2014-02-26 19:11:54 +01:00
|
|
|
/*-----------------------------*/
|
|
|
|
/* NOTE that the following fields may possess dynamically allocated
|
|
|
|
memory which should be freed if not needed anymore! */
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/** NULL, or a dynamically allocated buffer for old_rec */
|
|
|
|
byte* old_rec_buf;
|
|
|
|
/** old_rec_buf size if old_rec_buf is not NULL */
|
|
|
|
ulint buf_size;
|
2014-02-26 19:11:54 +01:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/** Return the index of this persistent cursor */
|
|
|
|
dict_index_t* index() const { return(btr_cur.index); }
|
|
|
|
};
|
2014-02-26 19:11:54 +01:00
|
|
|
|
|
|
|
#include "btr0pcur.ic"
|
|
|
|
|
|
|
|
#endif
|