mirror of
https://github.com/MariaDB/server.git
synced 2026-01-27 22:09:08 +01:00
- Introduce a class FTSQueryRunner to handle queries for fulltext
internal tables. Basically it creates a query, prepares the
fulltext internal table for read or write process. Build a tuple
based on the given table and assign the FTS_CONFIG, FTS_COMMON_TABLES
and FTS_AUX_TABLE fields based on the given value. This class
also handles INSERT, DELETE, REPLACE, UPDATE and
execute the function for each record (record_executor).
FTSQueryRunner::create_query_thread(): Create a query thread to execute
the statement on internal FULLTEXT tables
FTSQueryRunner::build_tuple(): Build a tuple for the operation
FTSQueryRunner::build_clust_ref(): Build a clustered index reference
for clustered index lookup for the secondary index record
FTSQueryRunner::assign_config_fields(): Assign the tuple for the
FTS CONFIG internal table
FTSQueryRunner::assign_common_table_fields(): Assign the tuple for
FTS_DELETED, FTS_DELETED_CACHE, FTS_BEGIN_DELETED,
FTS_BEGIN_DELETED_CACHE common tables
FTSQueryRunner::assign_aux_table_fields(): Assign the tuple for
FTS_PREFIX_INDEX tables.
FTSQueryRunner::handle_error(): Handling error for DB_LOCK_WAIT,
retry the operation
FTSQueryRunner::open_table(): Open the table based on the fulltext
auxiliary table name and FTS common table name
FTSQueryRunner::prepare_for_write(): Lock the table for write
process by taking Intention Exclusive lock
FTSQueryRunner::prepare_for_read(): Lock the table for read
process by taking Intention Shared lock
FTSQueryRunner::write_record(): Insert the tuple into the given table
FTSQueryRunner::lock_or_sees_rec(): Lock the record in case of
DELETE, SELECT_UPDATE operation. Fetch the correct version of record in
case of READ operation. It also does clustered index lookup in case
of search is on secondary index
fts_cmp_rec_dtuple_prefix(): Compare the record with given tuple field
for tuple field length
FTSQueryRunner::record_executor(): Read the record of the given index and
do call the callback function for each record
FTSQueryRunner::build_update_config(): Build the update vector for
FULLTEXT CONFIG table
FTSQueryRunner::update_record(): Update the record with update vector
exist in FTSQueryRunner
Removed the fts_parse_sql(), fts_eval_sql(), fts_get_select_columns_str()
and fts_get_docs_clear().
Moved fts_get_table_id() & fts_get_table_name() from fts0sql.cc to
fts0fts.cc and deleted the file fts0sql.cc
Removed ins_graph, sel_graph from fts_index_cache_t
Changed the callback function default read function parameter for
each clustered index record to
bool fts_sql_callback(dict_index_t*, const rec_t *, const rec_offs*,
void *);
Following parameters are changed to default read function parameter:
fts_read_stopword()
fts_fetch_store_doc_id()
fts_query_expansion_fetch_doc()
fts_read_count()
fts_get_rows_count()
fts_init_doc_id()
fts_init_recover_doc()
read_fts_config()
fts_optimize_read_node()
fts_optimize_index_fetch_node()
fts_index_fetch_nodes()
fts_fetch_index_words()
fts_index_fetch_words()
fts_fetch_doc_ids()
fts_table_fetch_doc_ids()
fts_read_ulint()
fts_copy_doc_ids()
fts_optimize_create_deleted_doc_id_snapshot()
fts_query_index_fetch_nodes()
fts_query_fetch_document()
fts_query_index_fetch_nodes()
row_upd_clust_rec_low(): Function does updates a clustered
index record of a row when ordering fields don't change.
Function doesn't have dependency on row_prebuilt_t. This can be
used by fulltext internal table update operation
Row_sel_get_clust_rec_for_mysql::operator(): Removed the
parameter row_prebuilt_t and caller does pass the prebuilt
related variables
Removed the parser usage and execute the query directly on
fulltext internal tables in the following function:
fts_read_stopword()
fts_fetch_store_doc_id()
fts_query_expansion_fetch_doc()
fts_read_count()
fts_get_rows_count()
fts_init_doc_id()
fts_init_recover_doc()
read_fts_config()
fts_optimize_read_node()
fts_optimize_index_fetch_node()
fts_index_fetch_nodes()
fts_fetch_index_words()
fts_index_fetch_words()
fts_fetch_doc_ids()
fts_table_fetch_doc_ids()
fts_read_ulint()
fts_copy_doc_ids()
fts_optimize_create_deleted_doc_id_snapshot()
fts_query_index_fetch_nodes()
fts_query_fetch_document()
fts_query_index_fetch_nodes()
i_s_fts_deleted_generic_fill()
i_s_fts_index_table_fill_selected()
501 lines
19 KiB
C++
501 lines
19 KiB
C++
/*****************************************************************************
|
|
|
|
Copyright (c) 1997, 2017, Oracle and/or its affiliates.
|
|
Copyright (c) 2017, 2022, MariaDB Corporation.
|
|
|
|
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, Fifth Floor, Boston, MA 02110-1335 USA
|
|
|
|
*****************************************************************************/
|
|
|
|
/**************************************************//**
|
|
@file include/row0sel.h
|
|
Select
|
|
|
|
Created 12/19/1997 Heikki Tuuri
|
|
*******************************************************/
|
|
|
|
#pragma once
|
|
|
|
#include "data0data.h"
|
|
#include "que0types.h"
|
|
#include "trx0types.h"
|
|
#include "read0types.h"
|
|
#include "row0types.h"
|
|
#include "que0types.h"
|
|
#include "pars0sym.h"
|
|
#include "btr0pcur.h"
|
|
#include "row0mysql.h"
|
|
|
|
/*********************************************************************//**
|
|
Creates a select node struct.
|
|
@return own: select node struct */
|
|
sel_node_t*
|
|
sel_node_create(
|
|
/*============*/
|
|
mem_heap_t* heap); /*!< in: memory heap where created */
|
|
/*********************************************************************//**
|
|
Frees the memory private to a select node when a query graph is freed,
|
|
does not free the heap where the node was originally created. */
|
|
void
|
|
sel_node_free_private(
|
|
/*==================*/
|
|
sel_node_t* node); /*!< in: select node struct */
|
|
/*********************************************************************//**
|
|
Frees a prefetch buffer for a column, including the dynamically allocated
|
|
memory for data stored there. */
|
|
void
|
|
sel_col_prefetch_buf_free(
|
|
/*======================*/
|
|
sel_buf_t* prefetch_buf); /*!< in, own: prefetch buffer */
|
|
/**********************************************************************//**
|
|
Performs a select step. This is a high-level function used in SQL execution
|
|
graphs.
|
|
@return query thread to run next or NULL */
|
|
que_thr_t*
|
|
row_sel_step(
|
|
/*=========*/
|
|
que_thr_t* thr); /*!< in: query thread */
|
|
/**********************************************************************//**
|
|
Performs a fetch for a cursor.
|
|
@return query thread to run next or NULL */
|
|
que_thr_t*
|
|
fetch_step(
|
|
/*=======*/
|
|
que_thr_t* thr); /*!< in: query thread */
|
|
/***********************************************************//**
|
|
Prints a row in a select result.
|
|
@return query thread to run next or NULL */
|
|
que_thr_t*
|
|
row_printf_step(
|
|
/*============*/
|
|
que_thr_t* thr); /*!< in: query thread */
|
|
|
|
/** Copy used fields from cached row.
|
|
Copy cache record field by field, don't touch fields that
|
|
are not covered by current key.
|
|
@param[out] buf Where to copy the MySQL row.
|
|
@param[in] cached_rec What to copy (in MySQL row format).
|
|
@param[in] prebuilt prebuilt struct. */
|
|
void
|
|
row_sel_copy_cached_fields_for_mysql(
|
|
byte* buf,
|
|
const byte* cached_rec,
|
|
row_prebuilt_t* prebuilt);
|
|
|
|
/****************************************************************//**
|
|
Converts a key value stored in MySQL format to an Innobase dtuple. The last
|
|
field of the key value may be just a prefix of a fixed length field: hence
|
|
the parameter key_len. But currently we do not allow search keys where the
|
|
last field is only a prefix of the full key field len and print a warning if
|
|
such appears. */
|
|
void
|
|
row_sel_convert_mysql_key_to_innobase(
|
|
/*==================================*/
|
|
dtuple_t* tuple, /*!< in/out: tuple where to build;
|
|
NOTE: we assume that the type info
|
|
in the tuple is already according
|
|
to index! */
|
|
byte* buf, /*!< in: buffer to use in field
|
|
conversions; NOTE that dtuple->data
|
|
may end up pointing inside buf so
|
|
do not discard that buffer while
|
|
the tuple is being used. See
|
|
row_mysql_store_col_in_innobase_format()
|
|
in the case of DATA_INT */
|
|
ulint buf_len, /*!< in: buffer length */
|
|
dict_index_t* index, /*!< in: index of the key value */
|
|
const byte* key_ptr, /*!< in: MySQL key value */
|
|
ulint key_len) /*!< in: MySQL key value length */
|
|
MY_ATTRIBUTE((nonnull(1,4,5)));
|
|
|
|
/** Search for rows in the database using cursor.
|
|
Function is mainly used for tables that are shared across connections and
|
|
so it employs technique that can help re-construct the rows that
|
|
transaction is suppose to see.
|
|
It also has optimization such as pre-caching the rows, using AHI, etc.
|
|
|
|
@param[out] buf buffer for the fetched row in MySQL format
|
|
@param[in] mode search mode PAGE_CUR_L
|
|
@param[in,out] prebuilt prebuilt struct for the table handler;
|
|
this contains the info to search_tuple,
|
|
index; if search tuple contains 0 field then
|
|
we position the cursor at start or the end of
|
|
index, depending on 'mode'
|
|
@param[in] match_mode 0 or ROW_SEL_EXACT or ROW_SEL_EXACT_PREFIX
|
|
@param[in] direction 0 or ROW_SEL_NEXT or ROW_SEL_PREV;
|
|
Note: if this is != 0, then prebuilt must has a
|
|
pcur with stored position! In opening of a
|
|
cursor 'direction' should be 0.
|
|
@return DB_SUCCESS, DB_RECORD_NOT_FOUND, DB_END_OF_INDEX, DB_DEADLOCK,
|
|
DB_LOCK_TABLE_FULL, DB_CORRUPTION, or DB_TOO_BIG_RECORD */
|
|
dberr_t
|
|
row_search_mvcc(
|
|
byte* buf,
|
|
page_cur_mode_t mode,
|
|
row_prebuilt_t* prebuilt,
|
|
ulint match_mode,
|
|
ulint direction)
|
|
MY_ATTRIBUTE((warn_unused_result));
|
|
|
|
/********************************************************************//**
|
|
Count rows in a R-Tree leaf level.
|
|
@return DB_SUCCESS if successful */
|
|
dberr_t
|
|
row_count_rtree_recs(
|
|
/*=================*/
|
|
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct for the
|
|
table handle; this contains the info
|
|
of search_tuple, index; if search
|
|
tuple contains 0 fields then we
|
|
position the cursor at the start or
|
|
the end of the index, depending on
|
|
'mode' */
|
|
ulint* n_rows); /*!< out: number of entries
|
|
seen in the consistent read */
|
|
|
|
/**
|
|
Check the index records in CHECK TABLE.
|
|
The index must contain entries in an ascending order,
|
|
unique constraint must not be violated by duplicated keys,
|
|
and the number of index entries is counted in according to the
|
|
current read view.
|
|
|
|
@param prebuilt index and transaction
|
|
@param n_rows number of records counted
|
|
|
|
@return error code
|
|
@retval DB_SUCCESS if no error was found */
|
|
dberr_t row_check_index(row_prebuilt_t *prebuilt, ulint *n_rows)
|
|
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
|
|
|
/** Read the max AUTOINC value from an index.
|
|
@param[in] index index starting with an AUTO_INCREMENT column
|
|
@return the largest AUTO_INCREMENT value
|
|
@retval 0 if no records were found */
|
|
uint64_t row_search_max_autoinc(dict_index_t *index) noexcept
|
|
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
|
|
|
/** A structure for caching column values for prefetched rows */
|
|
struct sel_buf_t{
|
|
byte* data; /*!< data, or NULL; if not NULL, this field
|
|
has allocated memory which must be explicitly
|
|
freed; can be != NULL even when len is
|
|
UNIV_SQL_NULL */
|
|
ulint len; /*!< data length or UNIV_SQL_NULL */
|
|
ulint val_buf_size;
|
|
/*!< size of memory buffer allocated for data:
|
|
this can be more than len; this is defined
|
|
when data != NULL */
|
|
};
|
|
|
|
/** Copy used fields from cached row.
|
|
Copy cache record field by field, don't touch fields that
|
|
are not covered by current key.
|
|
@param[out] buf Where to copy the MySQL row.
|
|
@param[in] cached_rec What to copy (in MySQL row format).
|
|
@param[in] prebuilt prebuilt struct. */
|
|
void
|
|
row_sel_copy_cached_fields_for_mysql(
|
|
byte* buf,
|
|
const byte* cached_rec,
|
|
row_prebuilt_t* prebuilt);
|
|
|
|
/** Query plan */
|
|
struct plan_t{
|
|
dict_table_t* table; /*!< table struct in the dictionary
|
|
cache */
|
|
dict_index_t* index; /*!< table index used in the search */
|
|
btr_pcur_t pcur; /*!< persistent cursor used to search
|
|
the index */
|
|
ibool asc; /*!< TRUE if cursor traveling upwards */
|
|
ibool pcur_is_open; /*!< TRUE if pcur has been positioned
|
|
and we can try to fetch new rows */
|
|
ibool cursor_at_end; /*!< TRUE if the cursor is open but
|
|
we know that there are no more
|
|
qualifying rows left to retrieve from
|
|
the index tree; NOTE though, that
|
|
there may still be unprocessed rows in
|
|
the prefetch stack; always FALSE when
|
|
pcur_is_open is FALSE */
|
|
ibool stored_cursor_rec_processed;
|
|
/*!< TRUE if the pcur position has been
|
|
stored and the record it is positioned
|
|
on has already been processed */
|
|
que_node_t** tuple_exps; /*!< array of expressions
|
|
which are used to calculate
|
|
the field values in the search
|
|
tuple: there is one expression
|
|
for each field in the search
|
|
tuple */
|
|
dtuple_t* tuple; /*!< search tuple */
|
|
page_cur_mode_t mode; /*!< search mode: PAGE_CUR_G, ... */
|
|
ulint n_exact_match; /*!< number of first fields in
|
|
the search tuple which must be
|
|
exactly matched */
|
|
ibool unique_search; /*!< TRUE if we are searching an
|
|
index record with a unique key */
|
|
ulint n_rows_fetched; /*!< number of rows fetched using pcur
|
|
after it was opened */
|
|
ulint n_rows_prefetched;/*!< number of prefetched rows cached
|
|
for fetch: fetching several rows in
|
|
the same mtr saves CPU time */
|
|
ulint first_prefetched;/*!< index of the first cached row in
|
|
select buffer arrays for each column */
|
|
ibool no_prefetch; /*!< no prefetch for this table */
|
|
sym_node_list_t columns; /*!< symbol table nodes for the columns
|
|
to retrieve from the table */
|
|
UT_LIST_BASE_NODE_T(func_node_t)
|
|
end_conds; /*!< conditions which determine the
|
|
fetch limit of the index segment we
|
|
have to look at: when one of these
|
|
fails, the result set has been
|
|
exhausted for the cursor in this
|
|
index; these conditions are normalized
|
|
so that in a comparison the column
|
|
for this table is the first argument */
|
|
UT_LIST_BASE_NODE_T(func_node_t)
|
|
other_conds; /*!< the rest of search conditions we can
|
|
test at this table in a join */
|
|
ibool must_get_clust; /*!< TRUE if index is a non-clustered
|
|
index and we must also fetch the
|
|
clustered index record; this is the
|
|
case if the non-clustered record does
|
|
not contain all the needed columns, or
|
|
if this is a single-table explicit
|
|
cursor, or a searched update or
|
|
delete */
|
|
ulint* clust_map; /*!< map telling how clust_ref is built
|
|
from the fields of a non-clustered
|
|
record */
|
|
dtuple_t* clust_ref; /*!< the reference to the clustered
|
|
index entry is built here if index is
|
|
a non-clustered index */
|
|
btr_pcur_t clust_pcur; /*!< if index is non-clustered, we use
|
|
this pcur to search the clustered
|
|
index */
|
|
mem_heap_t* old_vers_heap; /*!< memory heap used in building an old
|
|
version of a row, or NULL */
|
|
};
|
|
|
|
/** Select node states */
|
|
enum sel_node_state {
|
|
SEL_NODE_CLOSED, /*!< it is a declared cursor which is not
|
|
currently open */
|
|
SEL_NODE_OPEN, /*!< intention locks not yet set on tables */
|
|
SEL_NODE_FETCH, /*!< intention locks have been set */
|
|
SEL_NODE_NO_MORE_ROWS /*!< cursor has reached the result set end */
|
|
};
|
|
|
|
/** Select statement node */
|
|
struct sel_node_t{
|
|
que_common_t common; /*!< node type: QUE_NODE_SELECT */
|
|
enum sel_node_state
|
|
state; /*!< node state */
|
|
que_node_t* select_list; /*!< select list */
|
|
sym_node_t* into_list; /*!< variables list or NULL */
|
|
sym_node_t* table_list; /*!< table list */
|
|
ibool asc; /*!< TRUE if the rows should be fetched
|
|
in an ascending order */
|
|
ibool set_x_locks; /*!< TRUE if the cursor is for update or
|
|
delete, which means that a row x-lock
|
|
should be placed on the cursor row */
|
|
lock_mode row_lock_mode; /*!< LOCK_X or LOCK_S */
|
|
ulint n_tables; /*!< number of tables */
|
|
ulint fetch_table; /*!< number of the next table to access
|
|
in the join */
|
|
plan_t* plans; /*!< array of n_tables many plan nodes
|
|
containing the search plan and the
|
|
search data structures */
|
|
que_node_t* search_cond; /*!< search condition */
|
|
ReadView* read_view; /*!< if the query is a non-locking
|
|
consistent read, its read view is
|
|
placed here, otherwise NULL */
|
|
ibool consistent_read;/*!< TRUE if the select is a consistent,
|
|
non-locking read */
|
|
order_node_t* order_by; /*!< order by column definition, or
|
|
NULL */
|
|
ibool is_aggregate; /*!< TRUE if the select list consists of
|
|
aggregate functions */
|
|
ibool aggregate_already_fetched;
|
|
/*!< TRUE if the aggregate row has
|
|
already been fetched for the current
|
|
cursor */
|
|
ibool can_get_updated;/*!< this is TRUE if the select
|
|
is in a single-table explicit
|
|
cursor which can get updated
|
|
within the stored procedure,
|
|
or in a searched update or
|
|
delete; NOTE that to determine
|
|
of an explicit cursor if it
|
|
can get updated, the parser
|
|
checks from a stored procedure
|
|
if it contains positioned
|
|
update or delete statements */
|
|
sym_node_t* explicit_cursor;/*!< not NULL if an explicit cursor */
|
|
UT_LIST_BASE_NODE_T(sym_node_t)
|
|
copy_variables; /*!< variables whose values we have to
|
|
copy when an explicit cursor is opened,
|
|
so that they do not change between
|
|
fetches */
|
|
};
|
|
|
|
/**
|
|
Get the plan node for a table in a join.
|
|
@param node query graph node for SELECT
|
|
@param i plan node element
|
|
@return ith plan node */
|
|
inline plan_t *sel_node_get_nth_plan(sel_node_t *node, ulint i)
|
|
{
|
|
ut_ad(i < node->n_tables);
|
|
return &node->plans[i];
|
|
}
|
|
|
|
/** Fetch statement node */
|
|
struct fetch_node_t{
|
|
que_common_t common; /*!< type: QUE_NODE_FETCH */
|
|
sel_node_t* cursor_def; /*!< cursor definition */
|
|
sym_node_t* into_list; /*!< variables to set */
|
|
|
|
pars_user_func_t*
|
|
func; /*!< User callback function or NULL.
|
|
The first argument to the function
|
|
is a sel_node_t*, containing the
|
|
results of the SELECT operation for
|
|
one row. If the function returns
|
|
NULL, it is not interested in
|
|
further rows and the cursor is
|
|
modified so (cursor % NOTFOUND) is
|
|
true. If it returns not-NULL,
|
|
continue normally. */
|
|
};
|
|
|
|
/** Open or close cursor operation type */
|
|
enum open_node_op {
|
|
ROW_SEL_OPEN_CURSOR, /*!< open cursor */
|
|
ROW_SEL_CLOSE_CURSOR /*!< close cursor */
|
|
};
|
|
|
|
/** Open or close cursor statement node */
|
|
struct open_node_t{
|
|
que_common_t common; /*!< type: QUE_NODE_OPEN */
|
|
enum open_node_op
|
|
op_type; /*!< operation type: open or
|
|
close cursor */
|
|
sel_node_t* cursor_def; /*!< cursor definition */
|
|
};
|
|
|
|
/** Row printf statement node */
|
|
struct row_printf_node_t{
|
|
que_common_t common; /*!< type: QUE_NODE_ROW_PRINTF */
|
|
sel_node_t* sel_node; /*!< select */
|
|
};
|
|
|
|
/** Search direction for the MySQL interface */
|
|
enum row_sel_direction {
|
|
ROW_SEL_NEXT = 1, /*!< ascending direction */
|
|
ROW_SEL_PREV = 2 /*!< descending direction */
|
|
};
|
|
|
|
/** Match mode for the MySQL interface */
|
|
enum row_sel_match_mode {
|
|
ROW_SEL_EXACT = 1, /*!< search using a complete key value */
|
|
ROW_SEL_EXACT_PREFIX /*!< search using a key prefix which
|
|
must match rows: the prefix may
|
|
contain an incomplete field (the last
|
|
field in prefix may be just a prefix
|
|
of a fixed length column) */
|
|
};
|
|
|
|
#ifdef UNIV_DEBUG
|
|
/** Convert a non-SQL-NULL field from Innobase format to MySQL format. */
|
|
# define row_sel_field_store_in_mysql_format(dest,templ,idx,field,src,len) \
|
|
row_sel_field_store_in_mysql_format_func(dest,templ,idx,field,src,len)
|
|
#else /* UNIV_DEBUG */
|
|
/** Convert a non-SQL-NULL field from Innobase format to MySQL format. */
|
|
# define row_sel_field_store_in_mysql_format(dest,templ,idx,field,src,len) \
|
|
row_sel_field_store_in_mysql_format_func(dest,templ,src,len)
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
/**************************************************************//**
|
|
Stores a non-SQL-NULL field in the MySQL format. The counterpart of this
|
|
function is row_mysql_store_col_in_innobase_format() in row0mysql.cc. */
|
|
|
|
void
|
|
row_sel_field_store_in_mysql_format_func(
|
|
/*=====================================*/
|
|
byte* dest, /*!< in/out: buffer where to store; NOTE
|
|
that BLOBs are not in themselves
|
|
stored here: the caller must allocate
|
|
and copy the BLOB into buffer before,
|
|
and pass the pointer to the BLOB in
|
|
'data' */
|
|
const mysql_row_templ_t* templ,
|
|
/*!< in: MySQL column template.
|
|
Its following fields are referenced:
|
|
type, is_unsigned, mysql_col_len,
|
|
mbminlen, mbmaxlen */
|
|
#ifdef UNIV_DEBUG
|
|
const dict_index_t* index,
|
|
/*!< in: InnoDB index */
|
|
ulint field_no,
|
|
/*!< in: templ->rec_field_no or
|
|
templ->clust_rec_field_no or
|
|
templ->icp_rec_field_no */
|
|
#endif /* UNIV_DEBUG */
|
|
const byte* data, /*!< in: data to store */
|
|
ulint len); /*!< in: length of the data */
|
|
|
|
/** Helper class to cache clust_rec and old_vers */
|
|
class Row_sel_get_clust_rec_for_mysql
|
|
{
|
|
const rec_t *cached_clust_rec;
|
|
rec_t *cached_old_vers;
|
|
lsn_t cached_lsn;
|
|
page_id_t cached_page_id;
|
|
|
|
#ifdef UNIV_DEBUG
|
|
void check_eq(const dict_index_t *index, const rec_offs *offsets) const
|
|
{
|
|
rec_offs vers_offs[REC_OFFS_HEADER_SIZE + MAX_REF_PARTS];
|
|
rec_offs_init(vers_offs);
|
|
mem_heap_t *heap= nullptr;
|
|
|
|
ut_ad(rec_offs_validate(cached_clust_rec, index, offsets));
|
|
ut_ad(index->first_user_field() <= rec_offs_n_fields(offsets));
|
|
ut_ad(vers_offs == rec_get_offsets(cached_old_vers, index, vers_offs,
|
|
index->n_core_fields,
|
|
index->db_trx_id(), &heap));
|
|
ut_ad(!heap);
|
|
for (auto n= index->db_trx_id(); n--; )
|
|
{
|
|
const dict_col_t *col= dict_index_get_nth_col(index, n);
|
|
ulint len1, len2;
|
|
const byte *b1= rec_get_nth_field(cached_clust_rec, offsets, n, &len1);
|
|
const byte *b2= rec_get_nth_field(cached_old_vers, vers_offs, n, &len2);
|
|
ut_ad(!cmp_data(col->mtype, col->prtype, false, b1, len1, b2, len2));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
public:
|
|
Row_sel_get_clust_rec_for_mysql() :
|
|
cached_clust_rec(NULL), cached_old_vers(NULL), cached_lsn(0),
|
|
cached_page_id(page_id_t(0,0)) {}
|
|
|
|
dberr_t operator()(btr_pcur_t *clust_pcur, btr_pcur_t *pcur,
|
|
dtuple_t *clust_ref, lock_mode select_lock_type,
|
|
trx_t *trx, dict_index_t *sec_index,
|
|
const rec_t *rec, que_thr_t *thr, const rec_t **out_rec,
|
|
rec_offs **offsets, mem_heap_t **offset_heap,
|
|
mem_heap_t **old_vers_heap, dtuple_t **vrow, mtr_t *mtr);
|
|
};
|