mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 04:53:01 +01:00
1019 lines
28 KiB
Text
1019 lines
28 KiB
Text
/*****************************************************************************
|
|
|
|
Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
|
|
|
|
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/dict0dict.ic
|
|
Data dictionary system
|
|
|
|
Created 1/8/1996 Heikki Tuuri
|
|
***********************************************************************/
|
|
|
|
#include "data0type.h"
|
|
#ifndef UNIV_HOTBACKUP
|
|
#include "dict0load.h"
|
|
#include "rem0types.h"
|
|
#include "srv0srv.h"
|
|
|
|
/*********************************************************************//**
|
|
Gets the minimum number of bytes per character.
|
|
@return minimum multi-byte char size, in bytes */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_col_get_mbminlen(
|
|
/*==================*/
|
|
const dict_col_t* col) /*!< in: column */
|
|
{
|
|
return(DATA_MBMINLEN(col->mbminmaxlen));
|
|
}
|
|
/*********************************************************************//**
|
|
Gets the maximum number of bytes per character.
|
|
@return maximum multi-byte char size, in bytes */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_col_get_mbmaxlen(
|
|
/*==================*/
|
|
const dict_col_t* col) /*!< in: column */
|
|
{
|
|
return(DATA_MBMAXLEN(col->mbminmaxlen));
|
|
}
|
|
/*********************************************************************//**
|
|
Sets the minimum and maximum number of bytes per character. */
|
|
UNIV_INLINE
|
|
void
|
|
dict_col_set_mbminmaxlen(
|
|
/*=====================*/
|
|
dict_col_t* col, /*!< in/out: column */
|
|
ulint mbminlen, /*!< in: minimum multi-byte
|
|
character size, in bytes */
|
|
ulint mbmaxlen) /*!< in: minimum multi-byte
|
|
character size, in bytes */
|
|
{
|
|
ut_ad(mbminlen < DATA_MBMAX);
|
|
ut_ad(mbmaxlen < DATA_MBMAX);
|
|
ut_ad(mbminlen <= mbmaxlen);
|
|
|
|
col->mbminmaxlen = DATA_MBMINMAXLEN(mbminlen, mbmaxlen);
|
|
}
|
|
/*********************************************************************//**
|
|
Gets the column data type. */
|
|
UNIV_INLINE
|
|
void
|
|
dict_col_copy_type(
|
|
/*===============*/
|
|
const dict_col_t* col, /*!< in: column */
|
|
dtype_t* type) /*!< out: data type */
|
|
{
|
|
ut_ad(col && type);
|
|
|
|
type->mtype = col->mtype;
|
|
type->prtype = col->prtype;
|
|
type->len = col->len;
|
|
type->mbminmaxlen = col->mbminmaxlen;
|
|
}
|
|
#endif /* !UNIV_HOTBACKUP */
|
|
|
|
#ifdef UNIV_DEBUG
|
|
/*********************************************************************//**
|
|
Assert that a column and a data type match.
|
|
@return TRUE */
|
|
UNIV_INLINE
|
|
ibool
|
|
dict_col_type_assert_equal(
|
|
/*=======================*/
|
|
const dict_col_t* col, /*!< in: column */
|
|
const dtype_t* type) /*!< in: data type */
|
|
{
|
|
ut_ad(col);
|
|
ut_ad(type);
|
|
|
|
ut_ad(col->mtype == type->mtype);
|
|
ut_ad(col->prtype == type->prtype);
|
|
ut_ad(col->len == type->len);
|
|
# ifndef UNIV_HOTBACKUP
|
|
ut_ad(col->mbminmaxlen == type->mbminmaxlen);
|
|
# endif /* !UNIV_HOTBACKUP */
|
|
|
|
return(TRUE);
|
|
}
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
#ifndef UNIV_HOTBACKUP
|
|
/***********************************************************************//**
|
|
Returns the minimum size of the column.
|
|
@return minimum size */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_col_get_min_size(
|
|
/*==================*/
|
|
const dict_col_t* col) /*!< in: column */
|
|
{
|
|
return(dtype_get_min_size_low(col->mtype, col->prtype, col->len,
|
|
col->mbminmaxlen));
|
|
}
|
|
/***********************************************************************//**
|
|
Returns the maximum size of the column.
|
|
@return maximum size */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_col_get_max_size(
|
|
/*==================*/
|
|
const dict_col_t* col) /*!< in: column */
|
|
{
|
|
return(dtype_get_max_size_low(col->mtype, col->len));
|
|
}
|
|
#endif /* !UNIV_HOTBACKUP */
|
|
/***********************************************************************//**
|
|
Returns the size of a fixed size column, 0 if not a fixed size column.
|
|
@return fixed size, or 0 */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_col_get_fixed_size(
|
|
/*====================*/
|
|
const dict_col_t* col, /*!< in: column */
|
|
ulint comp) /*!< in: nonzero=ROW_FORMAT=COMPACT */
|
|
{
|
|
return(dtype_get_fixed_size_low(col->mtype, col->prtype, col->len,
|
|
col->mbminmaxlen, comp));
|
|
}
|
|
/***********************************************************************//**
|
|
Returns the ROW_FORMAT=REDUNDANT stored SQL NULL size of a column.
|
|
For fixed length types it is the fixed length of the type, otherwise 0.
|
|
@return SQL null storage size in ROW_FORMAT=REDUNDANT */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_col_get_sql_null_size(
|
|
/*=======================*/
|
|
const dict_col_t* col, /*!< in: column */
|
|
ulint comp) /*!< in: nonzero=ROW_FORMAT=COMPACT */
|
|
{
|
|
return(dict_col_get_fixed_size(col, comp));
|
|
}
|
|
|
|
/*********************************************************************//**
|
|
Gets the column number.
|
|
@return col->ind, table column position (starting from 0) */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_col_get_no(
|
|
/*============*/
|
|
const dict_col_t* col) /*!< in: column */
|
|
{
|
|
ut_ad(col);
|
|
|
|
return(col->ind);
|
|
}
|
|
|
|
/*********************************************************************//**
|
|
Gets the column position in the clustered index. */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_col_get_clust_pos(
|
|
/*===================*/
|
|
const dict_col_t* col, /*!< in: table column */
|
|
const dict_index_t* clust_index) /*!< in: clustered index */
|
|
{
|
|
ulint i;
|
|
|
|
ut_ad(col);
|
|
ut_ad(clust_index);
|
|
ut_ad(dict_index_is_clust(clust_index));
|
|
|
|
for (i = 0; i < clust_index->n_def; i++) {
|
|
const dict_field_t* field = &clust_index->fields[i];
|
|
|
|
if (!field->prefix_len && field->col == col) {
|
|
return(i);
|
|
}
|
|
}
|
|
|
|
return(ULINT_UNDEFINED);
|
|
}
|
|
|
|
#ifndef UNIV_HOTBACKUP
|
|
#ifdef UNIV_DEBUG
|
|
/********************************************************************//**
|
|
Gets the first index on the table (the clustered index).
|
|
@return index, NULL if none exists */
|
|
UNIV_INLINE
|
|
dict_index_t*
|
|
dict_table_get_first_index(
|
|
/*=======================*/
|
|
const dict_table_t* table) /*!< in: table */
|
|
{
|
|
ut_ad(table);
|
|
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
|
|
|
return(UT_LIST_GET_FIRST(((dict_table_t*) table)->indexes));
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Gets the next index on the table.
|
|
@return index, NULL if none left */
|
|
UNIV_INLINE
|
|
dict_index_t*
|
|
dict_table_get_next_index(
|
|
/*======================*/
|
|
const dict_index_t* index) /*!< in: index */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
|
|
return(UT_LIST_GET_NEXT(indexes, (dict_index_t*) index));
|
|
}
|
|
#endif /* UNIV_DEBUG */
|
|
#endif /* !UNIV_HOTBACKUP */
|
|
|
|
/********************************************************************//**
|
|
Check whether the index is the clustered index.
|
|
@return nonzero for clustered index, zero for other indexes */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_is_clust(
|
|
/*================*/
|
|
const dict_index_t* index) /*!< in: index */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
|
|
return(UNIV_UNLIKELY(index->type & DICT_CLUSTERED));
|
|
}
|
|
/********************************************************************//**
|
|
Check whether the index is unique.
|
|
@return nonzero for unique index, zero for other indexes */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_is_unique(
|
|
/*=================*/
|
|
const dict_index_t* index) /*!< in: index */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
|
|
return(UNIV_UNLIKELY(index->type & DICT_UNIQUE));
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Check whether the index is the insert buffer tree.
|
|
@return nonzero for insert buffer, zero for other indexes */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_is_ibuf(
|
|
/*===============*/
|
|
const dict_index_t* index) /*!< in: index */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
|
|
return(UNIV_UNLIKELY(index->type & DICT_IBUF));
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Check whether the index is a secondary index or the insert buffer tree.
|
|
@return nonzero for insert buffer, zero for other indexes */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_is_sec_or_ibuf(
|
|
/*======================*/
|
|
const dict_index_t* index) /*!< in: index */
|
|
{
|
|
ulint type;
|
|
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
|
|
type = index->type;
|
|
|
|
return(UNIV_LIKELY(!(type & DICT_CLUSTERED) || (type & DICT_IBUF)));
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Gets the number of user-defined columns in a table in the dictionary
|
|
cache.
|
|
@return number of user-defined (e.g., not ROW_ID) columns of a table */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_table_get_n_user_cols(
|
|
/*=======================*/
|
|
const dict_table_t* table) /*!< in: table */
|
|
{
|
|
ut_ad(table);
|
|
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
|
|
|
return(table->n_cols - DATA_N_SYS_COLS);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Gets the number of system columns in a table in the dictionary cache.
|
|
@return number of system (e.g., ROW_ID) columns of a table */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_table_get_n_sys_cols(
|
|
/*======================*/
|
|
const dict_table_t* table __attribute__((unused))) /*!< in: table */
|
|
{
|
|
ut_ad(table);
|
|
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
|
ut_ad(table->cached);
|
|
|
|
return(DATA_N_SYS_COLS);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Gets the number of all columns (also system) in a table in the dictionary
|
|
cache.
|
|
@return number of columns of a table */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_table_get_n_cols(
|
|
/*==================*/
|
|
const dict_table_t* table) /*!< in: table */
|
|
{
|
|
ut_ad(table);
|
|
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
|
|
|
return(table->n_cols);
|
|
}
|
|
|
|
#ifdef UNIV_DEBUG
|
|
/********************************************************************//**
|
|
Gets the nth column of a table.
|
|
@return pointer to column object */
|
|
UNIV_INLINE
|
|
dict_col_t*
|
|
dict_table_get_nth_col(
|
|
/*===================*/
|
|
const dict_table_t* table, /*!< in: table */
|
|
ulint pos) /*!< in: position of column */
|
|
{
|
|
ut_ad(table);
|
|
ut_ad(pos < table->n_def);
|
|
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
|
|
|
return((dict_col_t*) (table->cols) + pos);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Gets the given system column of a table.
|
|
@return pointer to column object */
|
|
UNIV_INLINE
|
|
dict_col_t*
|
|
dict_table_get_sys_col(
|
|
/*===================*/
|
|
const dict_table_t* table, /*!< in: table */
|
|
ulint sys) /*!< in: DATA_ROW_ID, ... */
|
|
{
|
|
dict_col_t* col;
|
|
|
|
ut_ad(table);
|
|
ut_ad(sys < DATA_N_SYS_COLS);
|
|
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
|
|
|
col = dict_table_get_nth_col(table, table->n_cols
|
|
- DATA_N_SYS_COLS + sys);
|
|
ut_ad(col->mtype == DATA_SYS);
|
|
ut_ad(col->prtype == (sys | DATA_NOT_NULL));
|
|
|
|
return(col);
|
|
}
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
/********************************************************************//**
|
|
Gets the given system column number of a table.
|
|
@return column number */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_table_get_sys_col_no(
|
|
/*======================*/
|
|
const dict_table_t* table, /*!< in: table */
|
|
ulint sys) /*!< in: DATA_ROW_ID, ... */
|
|
{
|
|
ut_ad(table);
|
|
ut_ad(sys < DATA_N_SYS_COLS);
|
|
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
|
|
|
return(table->n_cols - DATA_N_SYS_COLS + sys);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Check whether the table uses the compact page format.
|
|
@return TRUE if table uses the compact page format */
|
|
UNIV_INLINE
|
|
ibool
|
|
dict_table_is_comp(
|
|
/*===============*/
|
|
const dict_table_t* table) /*!< in: table */
|
|
{
|
|
ut_ad(table);
|
|
|
|
#if DICT_TF_COMPACT != TRUE
|
|
#error
|
|
#endif
|
|
|
|
return(UNIV_LIKELY(table->flags & DICT_TF_COMPACT));
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Determine the file format of a table.
|
|
@return file format version */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_table_get_format(
|
|
/*==================*/
|
|
const dict_table_t* table) /*!< in: table */
|
|
{
|
|
ut_ad(table);
|
|
|
|
return((table->flags & DICT_TF_FORMAT_MASK) >> DICT_TF_FORMAT_SHIFT);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Determine the file format of a table. */
|
|
UNIV_INLINE
|
|
void
|
|
dict_table_set_format(
|
|
/*==================*/
|
|
dict_table_t* table, /*!< in/out: table */
|
|
ulint format) /*!< in: file format version */
|
|
{
|
|
ut_ad(table);
|
|
|
|
table->flags = (table->flags & ~DICT_TF_FORMAT_MASK)
|
|
| (format << DICT_TF_FORMAT_SHIFT);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Extract the compressed page size from table flags.
|
|
@return compressed page size, or 0 if not compressed */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_table_flags_to_zip_size(
|
|
/*=========================*/
|
|
ulint flags) /*!< in: flags */
|
|
{
|
|
ulint zip_size = flags & DICT_TF_ZSSIZE_MASK;
|
|
|
|
if (UNIV_UNLIKELY(zip_size)) {
|
|
zip_size = ((PAGE_ZIP_MIN_SIZE >> 1)
|
|
<< (zip_size >> DICT_TF_ZSSIZE_SHIFT));
|
|
|
|
ut_ad(zip_size <= UNIV_PAGE_SIZE);
|
|
}
|
|
|
|
return(zip_size);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Check whether the table uses the compressed compact page format.
|
|
@return compressed page size, or 0 if not compressed */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_table_zip_size(
|
|
/*================*/
|
|
const dict_table_t* table) /*!< in: table */
|
|
{
|
|
ut_ad(table);
|
|
|
|
return(dict_table_flags_to_zip_size(table->flags));
|
|
}
|
|
|
|
#ifndef UNIV_HOTBACKUP
|
|
/*********************************************************************//**
|
|
Obtain exclusive locks on all index trees of the table. This is to prevent
|
|
accessing index trees while InnoDB is updating internal metadata for
|
|
operations such as truncate tables. */
|
|
UNIV_INLINE
|
|
void
|
|
dict_table_x_lock_indexes(
|
|
/*======================*/
|
|
dict_table_t* table) /*!< in: table */
|
|
{
|
|
dict_index_t* index;
|
|
|
|
ut_a(table);
|
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
|
|
|
/* Loop through each index of the table and lock them */
|
|
for (index = dict_table_get_first_index(table);
|
|
index != NULL;
|
|
index = dict_table_get_next_index(index)) {
|
|
rw_lock_x_lock(dict_index_get_lock(index));
|
|
}
|
|
}
|
|
|
|
/*********************************************************************//**
|
|
Release the exclusive locks on all index tree. */
|
|
UNIV_INLINE
|
|
void
|
|
dict_table_x_unlock_indexes(
|
|
/*========================*/
|
|
dict_table_t* table) /*!< in: table */
|
|
{
|
|
dict_index_t* index;
|
|
|
|
ut_a(table);
|
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
|
|
|
for (index = dict_table_get_first_index(table);
|
|
index != NULL;
|
|
index = dict_table_get_next_index(index)) {
|
|
rw_lock_x_unlock(dict_index_get_lock(index));
|
|
}
|
|
}
|
|
#endif /* !UNIV_HOTBACKUP */
|
|
/********************************************************************//**
|
|
Gets the number of fields in the internal representation of an index,
|
|
including fields added by the dictionary system.
|
|
@return number of fields */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_get_n_fields(
|
|
/*====================*/
|
|
const dict_index_t* index) /*!< in: an internal
|
|
representation of index (in
|
|
the dictionary cache) */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
|
|
return(index->n_fields);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Gets the number of fields in the internal representation of an index
|
|
that uniquely determine the position of an index entry in the index, if
|
|
we do not take multiversioning into account: in the B-tree use the value
|
|
returned by dict_index_get_n_unique_in_tree.
|
|
@return number of fields */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_get_n_unique(
|
|
/*====================*/
|
|
const dict_index_t* index) /*!< in: an internal representation
|
|
of index (in the dictionary cache) */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
ut_ad(index->cached);
|
|
|
|
return(index->n_uniq);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Gets the number of fields in the internal representation of an index
|
|
which uniquely determine the position of an index entry in the index, if
|
|
we also take multiversioning into account.
|
|
@return number of fields */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_get_n_unique_in_tree(
|
|
/*============================*/
|
|
const dict_index_t* index) /*!< in: an internal representation
|
|
of index (in the dictionary cache) */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
ut_ad(index->cached);
|
|
|
|
if (dict_index_is_clust(index)) {
|
|
|
|
return(dict_index_get_n_unique(index));
|
|
}
|
|
|
|
return(dict_index_get_n_fields(index));
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Gets the number of user-defined ordering fields in the index. In the internal
|
|
representation of clustered indexes we add the row id to the ordering fields
|
|
to make a clustered index unique, but this function returns the number of
|
|
fields the user defined in the index as ordering fields.
|
|
@return number of fields */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_get_n_ordering_defined_by_user(
|
|
/*======================================*/
|
|
const dict_index_t* index) /*!< in: an internal representation
|
|
of index (in the dictionary cache) */
|
|
{
|
|
return(index->n_user_defined_cols);
|
|
}
|
|
|
|
#ifdef UNIV_DEBUG
|
|
/********************************************************************//**
|
|
Gets the nth field of an index.
|
|
@return pointer to field object */
|
|
UNIV_INLINE
|
|
dict_field_t*
|
|
dict_index_get_nth_field(
|
|
/*=====================*/
|
|
const dict_index_t* index, /*!< in: index */
|
|
ulint pos) /*!< in: position of field */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(pos < index->n_def);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
|
|
return((dict_field_t*) (index->fields) + pos);
|
|
}
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
/********************************************************************//**
|
|
Returns the position of a system column in an index.
|
|
@return position, ULINT_UNDEFINED if not contained */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_get_sys_col_pos(
|
|
/*=======================*/
|
|
const dict_index_t* index, /*!< in: index */
|
|
ulint type) /*!< in: DATA_ROW_ID, ... */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
ut_ad(!(index->type & DICT_UNIVERSAL));
|
|
|
|
if (dict_index_is_clust(index)) {
|
|
|
|
return(dict_col_get_clust_pos(
|
|
dict_table_get_sys_col(index->table, type),
|
|
index));
|
|
}
|
|
|
|
return(dict_index_get_nth_col_pos(
|
|
index, dict_table_get_sys_col_no(index->table, type)));
|
|
}
|
|
|
|
/*********************************************************************//**
|
|
Gets the field column.
|
|
@return field->col, pointer to the table column */
|
|
UNIV_INLINE
|
|
const dict_col_t*
|
|
dict_field_get_col(
|
|
/*===============*/
|
|
const dict_field_t* field) /*!< in: index field */
|
|
{
|
|
ut_ad(field);
|
|
|
|
return(field->col);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Gets pointer to the nth column in an index.
|
|
@return column */
|
|
UNIV_INLINE
|
|
const dict_col_t*
|
|
dict_index_get_nth_col(
|
|
/*===================*/
|
|
const dict_index_t* index, /*!< in: index */
|
|
ulint pos) /*!< in: position of the field */
|
|
{
|
|
return(dict_field_get_col(dict_index_get_nth_field(index, pos)));
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Gets the column number the nth field in an index.
|
|
@return column number */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_get_nth_col_no(
|
|
/*======================*/
|
|
const dict_index_t* index, /*!< in: index */
|
|
ulint pos) /*!< in: position of the field */
|
|
{
|
|
return(dict_col_get_no(dict_index_get_nth_col(index, pos)));
|
|
}
|
|
|
|
#ifndef UNIV_HOTBACKUP
|
|
/********************************************************************//**
|
|
Returns the minimum data size of an index record.
|
|
@return minimum data size in bytes */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_get_min_size(
|
|
/*====================*/
|
|
const dict_index_t* index) /*!< in: index */
|
|
{
|
|
ulint n = dict_index_get_n_fields(index);
|
|
ulint size = 0;
|
|
|
|
while (n--) {
|
|
size += dict_col_get_min_size(dict_index_get_nth_col(index,
|
|
n));
|
|
}
|
|
|
|
return(size);
|
|
}
|
|
|
|
/*********************************************************************//**
|
|
Gets the space id of the root of the index tree.
|
|
@return space id */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_get_space(
|
|
/*=================*/
|
|
const dict_index_t* index) /*!< in: index */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
|
|
return(index->space);
|
|
}
|
|
|
|
/*********************************************************************//**
|
|
Sets the space id of the root of the index tree. */
|
|
UNIV_INLINE
|
|
void
|
|
dict_index_set_space(
|
|
/*=================*/
|
|
dict_index_t* index, /*!< in/out: index */
|
|
ulint space) /*!< in: space id */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
|
|
index->space = space;
|
|
}
|
|
|
|
/*********************************************************************//**
|
|
Gets the page number of the root of the index tree.
|
|
@return page number */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_get_page(
|
|
/*================*/
|
|
const dict_index_t* index) /*!< in: index */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
|
|
return(index->page);
|
|
}
|
|
|
|
/*********************************************************************//**
|
|
Gets the read-write lock of the index tree.
|
|
@return read-write lock */
|
|
UNIV_INLINE
|
|
rw_lock_t*
|
|
dict_index_get_lock(
|
|
/*================*/
|
|
dict_index_t* index) /*!< in: index */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
|
|
return(&(index->lock));
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Returns free space reserved for future updates of records. This is
|
|
relevant only in the case of many consecutive inserts, as updates
|
|
which make the records bigger might fragment the index.
|
|
@return number of free bytes on page, reserved for updates */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_get_space_reserve(void)
|
|
/*==============================*/
|
|
{
|
|
return(UNIV_PAGE_SIZE / 16);
|
|
}
|
|
|
|
/**********************************************************************//**
|
|
Checks if a table is in the dictionary cache.
|
|
@return table, NULL if not found */
|
|
UNIV_INLINE
|
|
dict_table_t*
|
|
dict_table_check_if_in_cache_low(
|
|
/*=============================*/
|
|
const char* table_name) /*!< in: table name */
|
|
{
|
|
dict_table_t* table;
|
|
ulint table_fold;
|
|
|
|
ut_ad(table_name);
|
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
|
|
|
/* Look for the table name in the hash table */
|
|
table_fold = ut_fold_string(table_name);
|
|
|
|
HASH_SEARCH(name_hash, dict_sys->table_hash, table_fold,
|
|
dict_table_t*, table, ut_ad(table->cached),
|
|
!strcmp(table->name, table_name));
|
|
|
|
/* make young in table_LRU */
|
|
if (table) {
|
|
UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
|
|
UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
|
|
}
|
|
|
|
return(table);
|
|
}
|
|
|
|
/**********************************************************************//**
|
|
Gets a table; loads it to the dictionary cache if necessary. A low-level
|
|
function.
|
|
@return table, NULL if not found */
|
|
UNIV_INLINE
|
|
dict_table_t*
|
|
dict_table_get_low(
|
|
/*===============*/
|
|
const char* table_name, /*!< in: table name */
|
|
dict_err_ignore_t
|
|
ignore_err) /*!< in: error to be ignored when
|
|
loading a table definition */
|
|
{
|
|
dict_table_t* table;
|
|
|
|
ut_ad(table_name);
|
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
|
|
|
table = dict_table_check_if_in_cache_low(table_name);
|
|
|
|
if (table && table->corrupted
|
|
&& !(ignore_err & DICT_ERR_IGNORE_CORRUPT)) {
|
|
fprintf(stderr, "InnoDB: table");
|
|
ut_print_name(stderr, NULL, TRUE, table->name);
|
|
if (srv_load_corrupted) {
|
|
fputs(" is corrupted, but"
|
|
" innodb_force_load_corrupted is set\n", stderr);
|
|
} else {
|
|
fputs(" is corrupted\n", stderr);
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
if (table == NULL) {
|
|
table = dict_load_table(table_name, TRUE, ignore_err);
|
|
}
|
|
|
|
ut_ad(!table || table->cached);
|
|
|
|
return(table);
|
|
}
|
|
|
|
/**********************************************************************//**
|
|
Returns a table object based on table id.
|
|
@return table, NULL if does not exist */
|
|
UNIV_INLINE
|
|
dict_table_t*
|
|
dict_table_get_on_id_low(
|
|
/*=====================*/
|
|
table_id_t table_id) /*!< in: table id */
|
|
{
|
|
dict_table_t* table;
|
|
ulint fold;
|
|
|
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
|
|
|
/* Look for the table name in the hash table */
|
|
fold = ut_fold_ull(table_id);
|
|
|
|
HASH_SEARCH(id_hash, dict_sys->table_id_hash, fold,
|
|
dict_table_t*, table, ut_ad(table->cached),
|
|
table->id == table_id);
|
|
if (table == NULL) {
|
|
table = dict_load_table_on_id(table_id);
|
|
}
|
|
|
|
/* make young in table_LRU */
|
|
if (table) {
|
|
UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
|
|
UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
|
|
}
|
|
|
|
ut_ad(!table || table->cached);
|
|
|
|
/* TODO: should get the type information from MySQL */
|
|
|
|
return(table);
|
|
}
|
|
|
|
/**********************************************************************//**
|
|
Determine bytes of column prefix to be stored in the undo log. Please
|
|
note if the table format is UNIV_FORMAT_A (< DICT_TF_FORMAT_ZIP), no prefix
|
|
needs to be stored in the undo log.
|
|
@return bytes of column prefix to be stored in the undo log */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_max_field_len_store_undo(
|
|
/*==========================*/
|
|
dict_table_t* table, /*!< in: table */
|
|
const dict_col_t* col) /*!< in: column which index prefix
|
|
is based on */
|
|
{
|
|
ulint prefix_len = 0;
|
|
|
|
if (dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP)
|
|
{
|
|
prefix_len = col->max_prefix
|
|
? col->max_prefix
|
|
: DICT_MAX_FIELD_LEN_BY_FORMAT(table);
|
|
}
|
|
|
|
return(prefix_len);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Check whether the table is corrupted.
|
|
@return nonzero for corrupted table, zero for valid tables */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_table_is_corrupted(
|
|
/*====================*/
|
|
const dict_table_t* table) /*!< in: table */
|
|
{
|
|
ut_ad(table);
|
|
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
|
|
|
return(UNIV_UNLIKELY(table->corrupted));
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Check whether the index is corrupted.
|
|
@return nonzero for corrupted index, zero for valid indexes */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_is_corrupted(
|
|
/*====================*/
|
|
const dict_index_t* index) /*!< in: index */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
|
|
return(UNIV_UNLIKELY((index->type & DICT_CORRUPT)
|
|
|| (index->table && index->table->corrupted)));
|
|
}
|
|
|
|
#endif /* !UNIV_HOTBACKUP */
|
|
/**********************************************************************//**
|
|
Compares the given foreign key identifier (the key in rb-tree) and the
|
|
foreign key identifier in the given fk object (value in rb-tree).
|
|
@return negative, 0, or positive if foreign_id is smaller, equal,
|
|
or greater than foreign_obj->id, respectively. */
|
|
UNIV_INLINE
|
|
int
|
|
dict_foreign_rbt_cmp(
|
|
/*=================*/
|
|
const void* foreign_id, /*!< in: the foreign key identifier
|
|
which is used as a key in rb-tree. */
|
|
const void* foreign_obj) /*!< in: the foreign object itself
|
|
which is used as value in rb-tree. */
|
|
{
|
|
return(ut_strcmp((const char*) foreign_id,
|
|
(*(dict_foreign_t**) foreign_obj)->id));
|
|
}
|
|
|
|
/**********************************************************************//**
|
|
Allocate the table->foreign_rbt, which stores all the foreign objects
|
|
that is available in table->foreign_list. The caller must hold the
|
|
dict_sys->mutex.
|
|
@return the allocated rbt object */
|
|
UNIV_INLINE
|
|
ib_rbt_t*
|
|
dict_table_init_foreign_rbt(
|
|
/*========================*/
|
|
dict_table_t* table) /*!< in: the table object whose
|
|
table->foreign_rbt will be initialized */
|
|
{
|
|
ut_a(table->foreign_rbt == NULL);
|
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
|
|
|
table->foreign_rbt = rbt_create(sizeof(dict_foreign_t*),
|
|
dict_foreign_rbt_cmp);
|
|
ut_a(table->foreign_rbt != NULL);
|
|
return(table->foreign_rbt);
|
|
}
|
|
|
|
/**********************************************************************//**
|
|
Allocate the table->referened_rbt, which stores all the foreign objects
|
|
that is available in table->referenced_list. The caller must hold the
|
|
dict_sys->mutex.
|
|
@return the allocated rbt object */
|
|
UNIV_INLINE
|
|
ib_rbt_t*
|
|
dict_table_init_referenced_rbt(
|
|
/*===========================*/
|
|
dict_table_t* table) /*!< in: the table object whose
|
|
table->referenced_rbt will be initialized */
|
|
{
|
|
ut_a(table->referenced_rbt == NULL);
|
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
|
|
|
table->referenced_rbt = rbt_create(sizeof(dict_foreign_t*),
|
|
dict_foreign_rbt_cmp);
|
|
ut_a(table->referenced_rbt != NULL);
|
|
return(table->referenced_rbt);
|
|
}
|