mirror of
https://github.com/MariaDB/server.git
synced 2025-01-19 05:22:25 +01:00
1583 lines
45 KiB
Text
1583 lines
45 KiB
Text
/*****************************************************************************
|
|
|
|
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
|
Copyright (c) 2013, 2014, SkySQL Ab. 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 "fsp0fsp.h"
|
|
#include "srv0srv.h"
|
|
#include "sync0rw.h" /* RW_S_LATCH */
|
|
|
|
/*********************************************************************//**
|
|
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 last index on the table.
|
|
@return index, NULL if none exists */
|
|
UNIV_INLINE
|
|
dict_index_t*
|
|
dict_table_get_last_index(
|
|
/*=======================*/
|
|
const dict_table_t* table) /*!< in: table */
|
|
{
|
|
ut_ad(table);
|
|
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
|
|
|
return(UT_LIST_GET_LAST((const_cast<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(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(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(index->type & DICT_IBUF);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Check whether the index is an universal index tree.
|
|
@return nonzero for universal tree, zero for other indexes */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_is_univ(
|
|
/*===============*/
|
|
const dict_index_t* index) /*!< in: index */
|
|
{
|
|
ut_ad(index);
|
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
|
|
|
return(index->type & DICT_UNIVERSAL);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
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(!(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);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Gets the approximately estimated number of rows in the table.
|
|
@return estimated number of rows */
|
|
UNIV_INLINE
|
|
ib_uint64_t
|
|
dict_table_get_n_rows(
|
|
/*==================*/
|
|
const dict_table_t* table) /*!< in: table */
|
|
{
|
|
ut_ad(table->stat_initialized);
|
|
|
|
return(table->stat_n_rows);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Increment the number of rows in the table by one.
|
|
Notice that this operation is not protected by any latch, the number is
|
|
approximate. */
|
|
UNIV_INLINE
|
|
void
|
|
dict_table_n_rows_inc(
|
|
/*==================*/
|
|
dict_table_t* table) /*!< in/out: table */
|
|
{
|
|
if (table->stat_initialized) {
|
|
ib_uint64_t n_rows = table->stat_n_rows;
|
|
if (n_rows < 0xFFFFFFFFFFFFFFFFULL) {
|
|
table->stat_n_rows = n_rows + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Decrement the number of rows in the table by one.
|
|
Notice that this operation is not protected by any latch, the number is
|
|
approximate. */
|
|
UNIV_INLINE
|
|
void
|
|
dict_table_n_rows_dec(
|
|
/*==================*/
|
|
dict_table_t* table) /*!< in/out: table */
|
|
{
|
|
if (table->stat_initialized) {
|
|
ib_uint64_t n_rows = table->stat_n_rows;
|
|
if (n_rows > 0) {
|
|
table->stat_n_rows = n_rows - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
#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 != 1
|
|
#error "DICT_TF_COMPACT must be 1"
|
|
#endif
|
|
|
|
return(table->flags & DICT_TF_COMPACT);
|
|
}
|
|
|
|
/************************************************************************
|
|
Check if the table has an FTS index. */
|
|
UNIV_INLINE
|
|
ibool
|
|
dict_table_has_fts_index(
|
|
/*=====================*/
|
|
/* out: TRUE if table has an FTS index */
|
|
dict_table_t* table) /* in: table */
|
|
{
|
|
ut_ad(table);
|
|
|
|
return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS));
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Validate the table flags.
|
|
@return true if valid. */
|
|
UNIV_INLINE
|
|
bool
|
|
dict_tf_is_valid(
|
|
/*=============*/
|
|
ulint flags) /*!< in: table flags */
|
|
{
|
|
ulint compact = DICT_TF_GET_COMPACT(flags);
|
|
ulint zip_ssize = DICT_TF_GET_ZIP_SSIZE(flags);
|
|
ulint atomic_blobs = DICT_TF_HAS_ATOMIC_BLOBS(flags);
|
|
ulint unused = DICT_TF_GET_UNUSED(flags);
|
|
ulint page_compression = DICT_TF_GET_PAGE_COMPRESSION(flags);
|
|
ulint page_compression_level = DICT_TF_GET_PAGE_COMPRESSION_LEVEL(flags);
|
|
ulint data_dir = DICT_TF_HAS_DATA_DIR(flags);
|
|
ulint atomic_writes = DICT_TF_GET_ATOMIC_WRITES(flags);
|
|
|
|
/* Make sure there are no bits that we do not know about. */
|
|
if (unused != 0) {
|
|
|
|
fprintf(stderr,
|
|
"InnoDB: Error: table unused flags are %ld"
|
|
" in the data dictionary and are corrupted\n"
|
|
"InnoDB: Error: data dictionary flags are\n"
|
|
"InnoDB: compact %ld atomic_blobs %ld\n"
|
|
"InnoDB: unused %ld data_dir %ld zip_ssize %ld\n"
|
|
"InnoDB: page_compression %ld page_compression_level %ld\n"
|
|
"InnoDB: atomic_writes %ld\n",
|
|
unused,
|
|
compact, atomic_blobs, unused, data_dir, zip_ssize,
|
|
page_compression, page_compression_level, atomic_writes
|
|
);
|
|
|
|
return(false);
|
|
|
|
} else if (atomic_blobs) {
|
|
/* Barracuda row formats COMPRESSED and DYNAMIC build on
|
|
the page structure introduced for the COMPACT row format
|
|
by allowing keys in secondary indexes to be made from
|
|
data stored off-page in the clustered index. */
|
|
|
|
if (!compact) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error: table compact flags are %ld"
|
|
" in the data dictionary and are corrupted\n"
|
|
"InnoDB: Error: data dictionary flags are\n"
|
|
"InnoDB: compact %ld atomic_blobs %ld\n"
|
|
"InnoDB: unused %ld data_dir %ld zip_ssize %ld\n"
|
|
"InnoDB: page_compression %ld page_compression_level %ld\n"
|
|
"InnoDB: atomic_writes %ld\n",
|
|
compact, compact, atomic_blobs, unused, data_dir, zip_ssize,
|
|
page_compression, page_compression_level, atomic_writes
|
|
);
|
|
|
|
return(false);
|
|
}
|
|
|
|
} else if (zip_ssize) {
|
|
|
|
/* Antelope does not support COMPRESSED row format. */
|
|
fprintf(stderr,
|
|
"InnoDB: Error: table flags are %ld"
|
|
" in the data dictionary and are corrupted\n"
|
|
"InnoDB: Error: data dictionary flags are\n"
|
|
"InnoDB: compact %ld atomic_blobs %ld\n"
|
|
"InnoDB: unused %ld data_dir %ld zip_ssize %ld\n"
|
|
"InnoDB: page_compression %ld page_compression_level %ld\n"
|
|
"InnoDB: atomic_writes %ld\n",
|
|
flags, compact, atomic_blobs, unused, data_dir, zip_ssize,
|
|
page_compression, page_compression_level, atomic_writes
|
|
);
|
|
|
|
return(false);
|
|
}
|
|
|
|
if (zip_ssize) {
|
|
|
|
/* COMPRESSED row format must have compact and atomic_blobs
|
|
bits set and validate the number is within allowed range. */
|
|
|
|
if (!compact
|
|
|| !atomic_blobs
|
|
|| zip_ssize > PAGE_ZIP_SSIZE_MAX) {
|
|
|
|
fprintf(stderr,
|
|
"InnoDB: Error: table compact flags are %ld in the data dictionary and are corrupted\n"
|
|
"InnoDB: Error: data dictionary flags are\n"
|
|
"InnoDB: compact %ld atomic_blobs %ld\n"
|
|
"InnoDB: unused %ld data_dir %ld zip_ssize %ld\n"
|
|
"InnoDB: page_compression %ld page_compression_level %ld\n"
|
|
"InnoDB: atomic_writes %ld\n",
|
|
flags,
|
|
compact, atomic_blobs, unused, data_dir, zip_ssize,
|
|
page_compression, page_compression_level, atomic_writes
|
|
|
|
);
|
|
return(false);
|
|
}
|
|
}
|
|
|
|
if (page_compression || page_compression_level) {
|
|
/* Page compression format must have compact and
|
|
atomic_blobs and page_compression_level requires
|
|
page_compression */
|
|
if (!compact
|
|
|| !page_compression
|
|
|| !atomic_blobs) {
|
|
|
|
fprintf(stderr,
|
|
"InnoDB: Error: table flags are %ld in the data dictionary and are corrupted\n"
|
|
"InnoDB: Error: data dictionary flags are\n"
|
|
"InnoDB: compact %ld atomic_blobs %ld\n"
|
|
"InnoDB: unused %ld data_dir %ld zip_ssize %ld\n"
|
|
"InnoDB: page_compression %ld page_compression_level %ld\n"
|
|
"InnoDB: atomic_writes %ld\n",
|
|
flags, compact, atomic_blobs, unused, data_dir, zip_ssize,
|
|
page_compression, page_compression_level, atomic_writes
|
|
);
|
|
|
|
return(false);
|
|
}
|
|
}
|
|
|
|
if (atomic_writes) {
|
|
|
|
if(atomic_writes < 0 || atomic_writes > ATOMIC_WRITES_OFF) {
|
|
|
|
fprintf(stderr,
|
|
"InnoDB: Error: table flags are %ld in the data dictionary and are corrupted\n"
|
|
"InnoDB: Error: data dictionary flags are\n"
|
|
"InnoDB: compact %ld atomic_blobs %ld\n"
|
|
"InnoDB: unused %ld data_dir %ld zip_ssize %ld\n"
|
|
"InnoDB: page_compression %ld page_compression_level %ld\n"
|
|
"InnoDB: atomic_writes %ld\n",
|
|
flags, compact, atomic_blobs, unused, data_dir, zip_ssize,
|
|
page_compression, page_compression_level, atomic_writes
|
|
);
|
|
return(false);
|
|
}
|
|
}
|
|
|
|
/* CREATE TABLE ... DATA DIRECTORY is supported for any row format,
|
|
so the DATA_DIR flag is compatible with all other table flags. */
|
|
|
|
return(true);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Validate a SYS_TABLES TYPE field and return it.
|
|
@return Same as input after validating it as a SYS_TABLES TYPE field.
|
|
If there is an error, return ULINT_UNDEFINED. */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_sys_tables_type_validate(
|
|
/*==========================*/
|
|
ulint type, /*!< in: SYS_TABLES.TYPE */
|
|
ulint n_cols) /*!< in: SYS_TABLES.N_COLS */
|
|
{
|
|
ulint low_order_bit = DICT_TF_GET_COMPACT(type);
|
|
ulint redundant = !(n_cols & DICT_N_COLS_COMPACT);
|
|
ulint zip_ssize = DICT_TF_GET_ZIP_SSIZE(type);
|
|
ulint atomic_blobs = DICT_TF_HAS_ATOMIC_BLOBS(type);
|
|
ulint unused = DICT_TF_GET_UNUSED(type);
|
|
ulint page_compression = DICT_TF_GET_PAGE_COMPRESSION(type);
|
|
ulint page_compression_level = DICT_TF_GET_PAGE_COMPRESSION_LEVEL(type);
|
|
ulint atomic_writes = DICT_TF_GET_ATOMIC_WRITES(type);
|
|
|
|
ut_a(atomic_writes >= 0 && atomic_writes <= ATOMIC_WRITES_OFF);
|
|
|
|
/* The low order bit of SYS_TABLES.TYPE is always set to 1.
|
|
If the format is UNIV_FORMAT_B or higher, this field is the same
|
|
as dict_table_t::flags. Zero is not allowed here. */
|
|
if (!low_order_bit) {
|
|
return(ULINT_UNDEFINED);
|
|
}
|
|
|
|
if (redundant) {
|
|
if (zip_ssize || atomic_blobs) {
|
|
fprintf(stderr, "InnoDB: Error: SYS_TABLES::TYPE=Redundant, zip_ssize %lu atomic_blobs %lu\n",
|
|
zip_ssize, atomic_blobs);
|
|
return(ULINT_UNDEFINED);
|
|
}
|
|
}
|
|
|
|
/* Make sure there are no bits that we do not know about. */
|
|
if (unused) {
|
|
fprintf(stderr, "InnoDB: Error: SYS_TABLES::TYPE=%lu, unused %lu\n",
|
|
type, unused);
|
|
return(ULINT_UNDEFINED);
|
|
}
|
|
|
|
if (atomic_blobs) {
|
|
/* Barracuda row formats COMPRESSED and DYNAMIC build on
|
|
the page structure introduced for the COMPACT row format
|
|
by allowing keys in secondary indexes to be made from
|
|
data stored off-page in the clustered index.
|
|
|
|
The DICT_N_COLS_COMPACT flag should be in N_COLS,
|
|
but we already know that. */
|
|
|
|
} else if (zip_ssize) {
|
|
/* Antelope does not support COMPRESSED format. */
|
|
fprintf(stderr, "InnoDB: Error: SYS_TABLES::TYPE=%lu, zip_ssize %lu\n",
|
|
type, zip_ssize);
|
|
return(ULINT_UNDEFINED);
|
|
}
|
|
|
|
if (zip_ssize) {
|
|
/* COMPRESSED row format must have low_order_bit and
|
|
atomic_blobs bits set and the DICT_N_COLS_COMPACT flag
|
|
should be in N_COLS, but we already know about the
|
|
low_order_bit and DICT_N_COLS_COMPACT flags. */
|
|
if (!atomic_blobs) {
|
|
fprintf(stderr, "InnoDB: Error: SYS_TABLES::TYPE=%lu, zip_ssize %lu atomic_blobs %lu\n",
|
|
type, zip_ssize, atomic_blobs);
|
|
return(ULINT_UNDEFINED);
|
|
}
|
|
|
|
/* Validate that the number is within allowed range. */
|
|
if (zip_ssize > PAGE_ZIP_SSIZE_MAX) {
|
|
fprintf(stderr, "InnoDB: Error: SYS_TABLES::TYPE=%lu, zip_ssize %lu max %d\n",
|
|
type, zip_ssize, PAGE_ZIP_SSIZE_MAX);
|
|
return(ULINT_UNDEFINED);
|
|
}
|
|
}
|
|
|
|
/* There is nothing to validate for the data_dir field.
|
|
CREATE TABLE ... DATA DIRECTORY is supported for any row
|
|
format, so the DATA_DIR flag is compatible with any other
|
|
table flags. However, it is not used with TEMPORARY tables.*/
|
|
|
|
if (page_compression || page_compression_level) {
|
|
/* page compressed row format must have low_order_bit and
|
|
atomic_blobs bits set and the DICT_N_COLS_COMPACT flag
|
|
should be in N_COLS, but we already know about the
|
|
low_order_bit and DICT_N_COLS_COMPACT flags. */
|
|
|
|
if (!atomic_blobs || !page_compression) {
|
|
fprintf(stderr, "InnoDB: Error: SYS_TABLES::TYPE=%lu, page_compression %lu page_compression_level %lu\n"
|
|
"InnoDB: Error: atomic_blobs %lu\n",
|
|
type, page_compression, page_compression_level, atomic_blobs);
|
|
return(ULINT_UNDEFINED);
|
|
}
|
|
}
|
|
|
|
/* Validate that the atomic writes number is within allowed range. */
|
|
if (atomic_writes < 0 || atomic_writes > ATOMIC_WRITES_OFF) {
|
|
fprintf(stderr, "InnoDB: Error: SYS_TABLES::TYPE=%lu, atomic_writes %lu\n",
|
|
type, atomic_writes);
|
|
return(ULINT_UNDEFINED);
|
|
}
|
|
|
|
/* Return the validated SYS_TABLES.TYPE. */
|
|
return(type);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Determine the file format from dict_table_t::flags
|
|
The low order bit will be zero for REDUNDANT and 1 for COMPACT. For any
|
|
other row_format, file_format is > 0 and DICT_TF_COMPACT will also be set.
|
|
@return file format version */
|
|
UNIV_INLINE
|
|
rec_format_t
|
|
dict_tf_get_rec_format(
|
|
/*===================*/
|
|
ulint flags) /*!< in: dict_table_t::flags */
|
|
{
|
|
ut_a(dict_tf_is_valid(flags));
|
|
|
|
if (!DICT_TF_GET_COMPACT(flags)) {
|
|
return(REC_FORMAT_REDUNDANT);
|
|
}
|
|
|
|
if (!DICT_TF_HAS_ATOMIC_BLOBS(flags)) {
|
|
return(REC_FORMAT_COMPACT);
|
|
}
|
|
|
|
if (DICT_TF_GET_ZIP_SSIZE(flags)) {
|
|
return(REC_FORMAT_COMPRESSED);
|
|
}
|
|
|
|
return(REC_FORMAT_DYNAMIC);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Determine the file format from a dict_table_t::flags.
|
|
@return file format version */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_tf_get_format(
|
|
/*===============*/
|
|
ulint flags) /*!< in: dict_table_t::flags */
|
|
{
|
|
if (DICT_TF_HAS_ATOMIC_BLOBS(flags)) {
|
|
return(UNIV_FORMAT_B);
|
|
}
|
|
|
|
return(UNIV_FORMAT_A);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
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(dict_tf_get_format(table->flags));
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Set the file format and zip size in a dict_table_t::flags. If zip size
|
|
is not needed, it should be 0. */
|
|
UNIV_INLINE
|
|
void
|
|
dict_tf_set(
|
|
/*========*/
|
|
ulint* flags, /*!< in/out: table flags */
|
|
rec_format_t format, /*!< in: file format */
|
|
ulint zip_ssize, /*!< in: zip shift size */
|
|
bool use_data_dir, /*!< in: table uses DATA DIRECTORY
|
|
*/
|
|
bool page_compressed,/*!< in: table uses page compressed
|
|
pages */
|
|
ulint page_compression_level, /*!< in: table page compression
|
|
level */
|
|
ulint atomic_writes) /*!< in: table atomic writes setup */
|
|
{
|
|
atomic_writes_t awrites = (atomic_writes_t)atomic_writes;
|
|
|
|
switch (format) {
|
|
case REC_FORMAT_REDUNDANT:
|
|
*flags = 0;
|
|
ut_ad(zip_ssize == 0);
|
|
break;
|
|
case REC_FORMAT_COMPACT:
|
|
*flags = DICT_TF_COMPACT;
|
|
ut_ad(zip_ssize == 0);
|
|
break;
|
|
case REC_FORMAT_COMPRESSED:
|
|
*flags = DICT_TF_COMPACT
|
|
| (1 << DICT_TF_POS_ATOMIC_BLOBS)
|
|
| (zip_ssize << DICT_TF_POS_ZIP_SSIZE);
|
|
break;
|
|
case REC_FORMAT_DYNAMIC:
|
|
*flags = DICT_TF_COMPACT
|
|
| (1 << DICT_TF_POS_ATOMIC_BLOBS);
|
|
ut_ad(zip_ssize == 0);
|
|
break;
|
|
}
|
|
|
|
if (use_data_dir) {
|
|
*flags |= (1 << DICT_TF_POS_DATA_DIR);
|
|
}
|
|
|
|
if (page_compressed) {
|
|
*flags |= (1 << DICT_TF_POS_ATOMIC_BLOBS)
|
|
| (1 << DICT_TF_POS_PAGE_COMPRESSION)
|
|
| (page_compression_level << DICT_TF_POS_PAGE_COMPRESSION_LEVEL);
|
|
|
|
ut_ad(zip_ssize == 0);
|
|
ut_ad(dict_tf_get_page_compression(*flags) == TRUE);
|
|
ut_ad(dict_tf_get_page_compression_level(*flags) == page_compression_level);
|
|
}
|
|
|
|
*flags |= (atomic_writes << DICT_TF_POS_ATOMIC_WRITES);
|
|
ut_a(dict_tf_get_atomic_writes(*flags) == awrites);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Convert a 32 bit integer table flags to the 32 bit integer that is
|
|
written into the tablespace header at the offset FSP_SPACE_FLAGS and is
|
|
also stored in the fil_space_t::flags field. The following chart shows
|
|
the translation of the low order bit. Other bits are the same.
|
|
========================= Low order bit ==========================
|
|
| REDUNDANT | COMPACT | COMPRESSED | DYNAMIC
|
|
dict_table_t::flags | 0 | 1 | 1 | 1
|
|
fil_space_t::flags | 0 | 0 | 1 | 1
|
|
==================================================================
|
|
@return tablespace flags (fil_space_t::flags) */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_tf_to_fsp_flags(
|
|
/*=================*/
|
|
ulint table_flags) /*!< in: dict_table_t::flags */
|
|
{
|
|
ulint fsp_flags;
|
|
ulint page_compression = DICT_TF_GET_PAGE_COMPRESSION(table_flags);
|
|
ulint page_compression_level = DICT_TF_GET_PAGE_COMPRESSION_LEVEL(table_flags);
|
|
ulint atomic_writes = DICT_TF_GET_ATOMIC_WRITES(table_flags);
|
|
|
|
DBUG_EXECUTE_IF("dict_tf_to_fsp_flags_failure",
|
|
return(ULINT_UNDEFINED););
|
|
|
|
/* Adjust bit zero. */
|
|
fsp_flags = DICT_TF_HAS_ATOMIC_BLOBS(table_flags) ? 1 : 0;
|
|
|
|
/* ZIP_SSIZE and ATOMIC_BLOBS are at the same position. */
|
|
fsp_flags |= table_flags & DICT_TF_MASK_ZIP_SSIZE;
|
|
fsp_flags |= table_flags & DICT_TF_MASK_ATOMIC_BLOBS;
|
|
|
|
/* In addition, tablespace flags also contain the page size. */
|
|
fsp_flags |= fsp_flags_set_page_size(fsp_flags, UNIV_PAGE_SIZE);
|
|
|
|
/* The DATA_DIR flag is in a different position in fsp_flag */
|
|
fsp_flags |= DICT_TF_HAS_DATA_DIR(table_flags)
|
|
? FSP_FLAGS_MASK_DATA_DIR : 0;
|
|
|
|
/* In addition, tablespace flags also contain if the page
|
|
compression is used for this table. */
|
|
fsp_flags |= FSP_FLAGS_SET_PAGE_COMPRESSION(fsp_flags, page_compression);
|
|
|
|
/* In addition, tablespace flags also contain page compression level
|
|
if page compression is used for this table. */
|
|
fsp_flags |= FSP_FLAGS_SET_PAGE_COMPRESSION_LEVEL(fsp_flags, page_compression_level);
|
|
|
|
/* In addition, tablespace flags also contain flag if atomic writes
|
|
is used for this table */
|
|
fsp_flags |= FSP_FLAGS_SET_ATOMIC_WRITES(fsp_flags, atomic_writes);
|
|
|
|
ut_a(fsp_flags_is_valid(fsp_flags));
|
|
ut_a(dict_tf_verify_flags(table_flags, fsp_flags));
|
|
|
|
return(fsp_flags);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Convert a 32 bit integer from SYS_TABLES.TYPE to dict_table_t::flags
|
|
The following chart shows the translation of the low order bit.
|
|
Other bits are the same.
|
|
========================= Low order bit ==========================
|
|
| REDUNDANT | COMPACT | COMPRESSED and DYNAMIC
|
|
SYS_TABLES.TYPE | 1 | 1 | 1
|
|
dict_table_t::flags | 0 | 1 | 1
|
|
==================================================================
|
|
@return ulint containing SYS_TABLES.TYPE */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_sys_tables_type_to_tf(
|
|
/*=======================*/
|
|
ulint type, /*!< in: SYS_TABLES.TYPE field */
|
|
ulint n_cols) /*!< in: SYS_TABLES.N_COLS field */
|
|
{
|
|
ulint flags;
|
|
ulint redundant = !(n_cols & DICT_N_COLS_COMPACT);
|
|
|
|
/* Adjust bit zero. */
|
|
flags = redundant ? 0 : 1;
|
|
|
|
/* ZIP_SSIZE, ATOMIC_BLOBS, DATA_DIR, PAGE_COMPRESSION,
|
|
PAGE_COMPRESSION_LEVEL, ATOMIC_WRITES are the same. */
|
|
flags |= type & (DICT_TF_MASK_ZIP_SSIZE
|
|
| DICT_TF_MASK_ATOMIC_BLOBS
|
|
| DICT_TF_MASK_DATA_DIR
|
|
| DICT_TF_MASK_PAGE_COMPRESSION
|
|
| DICT_TF_MASK_PAGE_COMPRESSION_LEVEL
|
|
| DICT_TF_MASK_ATOMIC_WRITES
|
|
);
|
|
|
|
return(flags);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Convert a 32 bit integer table flags to the 32bit integer that is written
|
|
to a SYS_TABLES.TYPE field. The following chart shows the translation of
|
|
the low order bit. Other bits are the same.
|
|
========================= Low order bit ==========================
|
|
| REDUNDANT | COMPACT | COMPRESSED and DYNAMIC
|
|
dict_table_t::flags | 0 | 1 | 1
|
|
SYS_TABLES.TYPE | 1 | 1 | 1
|
|
==================================================================
|
|
@return ulint containing SYS_TABLES.TYPE */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_tf_to_sys_tables_type(
|
|
/*=======================*/
|
|
ulint flags) /*!< in: dict_table_t::flags */
|
|
{
|
|
ulint type;
|
|
|
|
ut_a(dict_tf_is_valid(flags));
|
|
|
|
/* Adjust bit zero. It is always 1 in SYS_TABLES.TYPE */
|
|
type = 1;
|
|
|
|
/* ZIP_SSIZE, ATOMIC_BLOBS, DATA_DIR, PAGE_COMPRESSION,
|
|
PAGE_COMPRESSION_LEVEL, ATOMIC_WRITES are the same. */
|
|
type |= flags & (DICT_TF_MASK_ZIP_SSIZE
|
|
| DICT_TF_MASK_ATOMIC_BLOBS
|
|
| DICT_TF_MASK_DATA_DIR
|
|
| DICT_TF_MASK_PAGE_COMPRESSION
|
|
| DICT_TF_MASK_PAGE_COMPRESSION_LEVEL
|
|
| DICT_TF_MASK_ATOMIC_WRITES);
|
|
|
|
return(type);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Extract the compressed page size from dict_table_t::flags.
|
|
These flags are in memory, so assert that they are valid.
|
|
@return compressed page size, or 0 if not compressed */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_tf_get_zip_size(
|
|
/*=================*/
|
|
ulint flags) /*!< in: flags */
|
|
{
|
|
ulint zip_ssize = DICT_TF_GET_ZIP_SSIZE(flags);
|
|
ulint zip_size = (zip_ssize
|
|
? (UNIV_ZIP_SIZE_MIN >> 1) << zip_ssize
|
|
: 0);
|
|
|
|
ut_ad(zip_size <= UNIV_ZIP_SIZE_MAX);
|
|
|
|
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_tf_get_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(!dict_index_is_univ(index));
|
|
|
|
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)));
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Looks for column n in an index.
|
|
@return position in internal representation of the index;
|
|
ULINT_UNDEFINED if not contained */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_index_get_nth_col_pos(
|
|
/*=======================*/
|
|
const dict_index_t* index, /*!< in: index */
|
|
ulint n) /*!< in: column number */
|
|
{
|
|
return(dict_index_get_nth_col_or_prefix_pos(index, n, FALSE));
|
|
}
|
|
|
|
#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
|
|
prio_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);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Gets the status of online index creation.
|
|
@return the status */
|
|
UNIV_INLINE
|
|
enum online_index_status
|
|
dict_index_get_online_status(
|
|
/*=========================*/
|
|
const dict_index_t* index) /*!< in: secondary index */
|
|
{
|
|
enum online_index_status status;
|
|
|
|
status = (enum online_index_status) index->online_status;
|
|
|
|
/* Without the index->lock protection, the online
|
|
status can change from ONLINE_INDEX_CREATION to
|
|
ONLINE_INDEX_COMPLETE (or ONLINE_INDEX_ABORTED) in
|
|
row_log_apply() once log application is done. So to make
|
|
sure the status is ONLINE_INDEX_CREATION or ONLINE_INDEX_COMPLETE
|
|
you should always do the recheck after acquiring index->lock */
|
|
|
|
#ifdef UNIV_DEBUG
|
|
switch (status) {
|
|
case ONLINE_INDEX_COMPLETE:
|
|
case ONLINE_INDEX_CREATION:
|
|
case ONLINE_INDEX_ABORTED:
|
|
case ONLINE_INDEX_ABORTED_DROPPED:
|
|
return(status);
|
|
}
|
|
ut_error;
|
|
#endif /* UNIV_DEBUG */
|
|
return(status);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Sets the status of online index creation. */
|
|
UNIV_INLINE
|
|
void
|
|
dict_index_set_online_status(
|
|
/*=========================*/
|
|
dict_index_t* index, /*!< in/out: index */
|
|
enum online_index_status status) /*!< in: status */
|
|
{
|
|
ut_ad(!(index->type & DICT_FTS));
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
ut_ad(rw_lock_own(dict_index_get_lock(index), RW_LOCK_EX));
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
#ifdef UNIV_DEBUG
|
|
switch (dict_index_get_online_status(index)) {
|
|
case ONLINE_INDEX_COMPLETE:
|
|
case ONLINE_INDEX_CREATION:
|
|
break;
|
|
case ONLINE_INDEX_ABORTED:
|
|
ut_ad(status == ONLINE_INDEX_ABORTED_DROPPED);
|
|
break;
|
|
case ONLINE_INDEX_ABORTED_DROPPED:
|
|
ut_error;
|
|
}
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
index->online_status = status;
|
|
ut_ad(dict_index_get_online_status(index) == status);
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Determines if a secondary index is being or has been created online,
|
|
or if the table is being rebuilt online, allowing concurrent modifications
|
|
to the table.
|
|
@retval true if the index is being or has been built online, or
|
|
if this is a clustered index and the table is being or has been rebuilt online
|
|
@retval false if the index has been created or the table has been
|
|
rebuilt completely */
|
|
UNIV_INLINE
|
|
bool
|
|
dict_index_is_online_ddl(
|
|
/*=====================*/
|
|
const dict_index_t* index) /*!< in: index */
|
|
{
|
|
#ifdef UNIV_DEBUG
|
|
if (dict_index_is_clust(index)) {
|
|
switch (dict_index_get_online_status(index)) {
|
|
case ONLINE_INDEX_CREATION:
|
|
return(true);
|
|
case ONLINE_INDEX_COMPLETE:
|
|
return(false);
|
|
case ONLINE_INDEX_ABORTED:
|
|
case ONLINE_INDEX_ABORTED_DROPPED:
|
|
break;
|
|
}
|
|
ut_ad(0);
|
|
return(false);
|
|
}
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
return(UNIV_UNLIKELY(dict_index_get_online_status(index)
|
|
!= ONLINE_INDEX_COMPLETE));
|
|
}
|
|
|
|
/**********************************************************************//**
|
|
Check whether a column exists in an FTS index.
|
|
@return ULINT_UNDEFINED if no match else the offset within the vector */
|
|
UNIV_INLINE
|
|
ulint
|
|
dict_table_is_fts_column(
|
|
/*=====================*/
|
|
ib_vector_t* indexes,/*!< in: vector containing only FTS indexes */
|
|
ulint col_no) /*!< in: col number to search for */
|
|
|
|
{
|
|
ulint i;
|
|
|
|
for (i = 0; i < ib_vector_size(indexes); ++i) {
|
|
dict_index_t* index;
|
|
|
|
index = (dict_index_t*) ib_vector_getp(indexes, i);
|
|
|
|
if (dict_index_contains_col_or_prefix(index, col_no)) {
|
|
|
|
return(i);
|
|
}
|
|
}
|
|
|
|
return(ULINT_UNDEFINED);
|
|
}
|
|
|
|
/**********************************************************************//**
|
|
Determine bytes of column prefix to be stored in the undo log. Please
|
|
note if the table format is UNIV_FORMAT_A (< UNIV_FORMAT_B), 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) >= UNIV_FORMAT_B)
|
|
{
|
|
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(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((index->type & DICT_CORRUPT)
|
|
|| (index->table && index->table->corrupted));
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Check if the tablespace for the table has been discarded.
|
|
@return true if the tablespace has been discarded. */
|
|
UNIV_INLINE
|
|
bool
|
|
dict_table_is_discarded(
|
|
/*====================*/
|
|
const dict_table_t* table) /*!< in: table to check */
|
|
{
|
|
return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_DISCARDED));
|
|
}
|
|
|
|
/********************************************************************//**
|
|
Check if it is a temporary table.
|
|
@return true if temporary table flag is set. */
|
|
UNIV_INLINE
|
|
bool
|
|
dict_table_is_temporary(
|
|
/*====================*/
|
|
const dict_table_t* table) /*!< in: table to check */
|
|
{
|
|
return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY));
|
|
}
|
|
|
|
#endif /* !UNIV_HOTBACKUP */
|