mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
6566 lines
169 KiB
C++
6566 lines
169 KiB
C++
/*****************************************************************************
|
|
|
|
Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
|
Copyright (c) 2014, 2023, 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 handler/i_s.cc
|
|
InnoDB INFORMATION SCHEMA tables interface to MySQL.
|
|
|
|
Created July 18, 2007 Vasil Dimov
|
|
*******************************************************/
|
|
|
|
#include "univ.i"
|
|
#include <mysql_version.h>
|
|
#include <field.h>
|
|
|
|
#include <sql_acl.h>
|
|
#include <sql_show.h>
|
|
#include <sql_time.h>
|
|
|
|
#include "i_s.h"
|
|
#include "btr0pcur.h"
|
|
#include "btr0types.h"
|
|
#include "dict0dict.h"
|
|
#include "dict0load.h"
|
|
#include "buf0buddy.h"
|
|
#include "buf0buf.h"
|
|
#include "dict0mem.h"
|
|
#include "dict0types.h"
|
|
#include "srv0start.h"
|
|
#include "trx0i_s.h"
|
|
#include "trx0trx.h"
|
|
#include "srv0mon.h"
|
|
#include "pars0pars.h"
|
|
#include "fts0types.h"
|
|
#include "fts0opt.h"
|
|
#include "fts0priv.h"
|
|
#include "btr0btr.h"
|
|
#include "page0zip.h"
|
|
#include "fil0fil.h"
|
|
#include "fil0crypt.h"
|
|
#include "dict0crea.h"
|
|
#include "fts0vlc.h"
|
|
#include "scope.h"
|
|
#include "log.h"
|
|
|
|
/** The latest successfully looked up innodb_fts_aux_table */
|
|
table_id_t innodb_ft_aux_table_id;
|
|
|
|
/** structure associates a name string with a file page type and/or buffer
|
|
page state. */
|
|
struct buf_page_desc_t{
|
|
const char* type_str; /*!< String explain the page
|
|
type/state */
|
|
ulint type_value; /*!< Page type or page state */
|
|
};
|
|
|
|
/** We also define I_S_PAGE_TYPE_INDEX as the Index Page's position
|
|
in i_s_page_type[] array */
|
|
#define I_S_PAGE_TYPE_INDEX 1
|
|
|
|
/** Any unassigned FIL_PAGE_TYPE will be treated as unknown. */
|
|
#define I_S_PAGE_TYPE_UNKNOWN FIL_PAGE_TYPE_UNKNOWN
|
|
|
|
/** R-tree index page */
|
|
#define I_S_PAGE_TYPE_RTREE (FIL_PAGE_TYPE_LAST + 1)
|
|
|
|
#define I_S_PAGE_TYPE_LAST I_S_PAGE_TYPE_RTREE
|
|
|
|
#define I_S_PAGE_TYPE_BITS 4
|
|
|
|
/** Name string for File Page Types */
|
|
static buf_page_desc_t i_s_page_type[] = {
|
|
{"ALLOCATED", FIL_PAGE_TYPE_ALLOCATED},
|
|
{"INDEX", FIL_PAGE_INDEX},
|
|
{"UNDO_LOG", FIL_PAGE_UNDO_LOG},
|
|
{"INODE", FIL_PAGE_INODE},
|
|
{"IBUF_FREE_LIST", FIL_PAGE_IBUF_FREE_LIST},
|
|
{"IBUF_BITMAP", FIL_PAGE_IBUF_BITMAP},
|
|
{"SYSTEM", FIL_PAGE_TYPE_SYS},
|
|
{"TRX_SYSTEM", FIL_PAGE_TYPE_TRX_SYS},
|
|
{"FILE_SPACE_HEADER", FIL_PAGE_TYPE_FSP_HDR},
|
|
{"EXTENT_DESCRIPTOR", FIL_PAGE_TYPE_XDES},
|
|
{"BLOB", FIL_PAGE_TYPE_BLOB},
|
|
{"COMPRESSED_BLOB", FIL_PAGE_TYPE_ZBLOB},
|
|
{"COMPRESSED_BLOB2", FIL_PAGE_TYPE_ZBLOB2},
|
|
{"UNKNOWN", I_S_PAGE_TYPE_UNKNOWN},
|
|
{"RTREE_INDEX", I_S_PAGE_TYPE_RTREE},
|
|
};
|
|
|
|
/** This structure defines information we will fetch from pages
|
|
currently cached in the buffer pool. It will be used to populate
|
|
table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE */
|
|
struct buf_page_info_t{
|
|
ulint block_id; /*!< Buffer Pool block ID */
|
|
/** page identifier */
|
|
page_id_t id;
|
|
uint32_t access_time; /*!< Time of first access */
|
|
uint32_t state; /*!< buf_page_t::state() */
|
|
#ifdef BTR_CUR_HASH_ADAPT
|
|
unsigned hashed:1; /*!< Whether hash index has been
|
|
built on this page */
|
|
#endif /* BTR_CUR_HASH_ADAPT */
|
|
unsigned is_old:1; /*!< TRUE if the block is in the old
|
|
blocks in buf_pool.LRU_old */
|
|
unsigned freed_page_clock:31; /*!< the value of
|
|
buf_pool.freed_page_clock */
|
|
unsigned zip_ssize:PAGE_ZIP_SSIZE_BITS;
|
|
/*!< Compressed page size */
|
|
unsigned compressed_only:1; /*!< ROW_FORMAT=COMPRESSED only */
|
|
unsigned page_type:I_S_PAGE_TYPE_BITS; /*!< Page type */
|
|
unsigned num_recs:UNIV_PAGE_SIZE_SHIFT_MAX-2;
|
|
/*!< Number of records on Page */
|
|
unsigned data_size:UNIV_PAGE_SIZE_SHIFT_MAX;
|
|
/*!< Sum of the sizes of the records */
|
|
lsn_t newest_mod; /*!< Log sequence number of
|
|
the youngest modification */
|
|
lsn_t oldest_mod; /*!< Log sequence number of
|
|
the oldest modification */
|
|
index_id_t index_id; /*!< Index ID if a index page */
|
|
};
|
|
|
|
/*
|
|
Use the following types mapping:
|
|
|
|
C type ST_FIELD_INFO::field_type
|
|
---------------------------------
|
|
long MYSQL_TYPE_LONGLONG
|
|
(field_length=MY_INT64_NUM_DECIMAL_DIGITS)
|
|
|
|
long unsigned MYSQL_TYPE_LONGLONG
|
|
(field_length=MY_INT64_NUM_DECIMAL_DIGITS, field_flags=MY_I_S_UNSIGNED)
|
|
|
|
char* MYSQL_TYPE_STRING
|
|
(field_length=n)
|
|
|
|
float MYSQL_TYPE_FLOAT
|
|
(field_length=0 is ignored)
|
|
|
|
void* MYSQL_TYPE_LONGLONG
|
|
(field_length=MY_INT64_NUM_DECIMAL_DIGITS, field_flags=MY_I_S_UNSIGNED)
|
|
|
|
boolean (if else) MYSQL_TYPE_LONG
|
|
(field_length=1)
|
|
|
|
time_t MYSQL_TYPE_DATETIME
|
|
(field_length=0 ignored)
|
|
---------------------------------
|
|
*/
|
|
|
|
/**
|
|
Common function to fill any of the dynamic tables:
|
|
INFORMATION_SCHEMA.innodb_trx
|
|
INFORMATION_SCHEMA.innodb_locks
|
|
INFORMATION_SCHEMA.innodb_lock_waits
|
|
@retval false if access to the table is blocked
|
|
@retval true if something should be filled in */
|
|
static bool trx_i_s_common_fill_table(THD *thd, TABLE_LIST *tables)
|
|
{
|
|
DBUG_ENTER("trx_i_s_common_fill_table");
|
|
|
|
/* deny access to non-superusers */
|
|
if (check_global_access(thd, PROCESS_ACL))
|
|
DBUG_RETURN(false);
|
|
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
/* update the cache */
|
|
trx_i_s_cache_start_write(trx_i_s_cache);
|
|
trx_i_s_possibly_fetch_data_into_cache(trx_i_s_cache);
|
|
trx_i_s_cache_end_write(trx_i_s_cache);
|
|
|
|
if (trx_i_s_cache_is_truncated(trx_i_s_cache))
|
|
sql_print_warning("InnoDB: Data in %.*s truncated due to memory limit"
|
|
" of %u bytes",
|
|
int(tables->schema_table_name.length),
|
|
tables->schema_table_name.str,
|
|
TRX_I_S_MEM_LIMIT);
|
|
|
|
DBUG_RETURN(true);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Unbind a dynamic INFORMATION_SCHEMA table.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_common_deinit(
|
|
/*==============*/
|
|
void* p); /*!< in/out: table schema object */
|
|
/*******************************************************************//**
|
|
Auxiliary function to store time_t value in MYSQL_TYPE_DATETIME
|
|
field.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
field_store_time_t(
|
|
/*===============*/
|
|
Field* field, /*!< in/out: target field for storage */
|
|
time_t time) /*!< in: value to store */
|
|
{
|
|
MYSQL_TIME my_time;
|
|
struct tm tm_time;
|
|
|
|
if (time) {
|
|
#if 0
|
|
/* use this if you are sure that `variables' and `time_zone'
|
|
are always initialized */
|
|
thd->variables.time_zone->gmt_sec_to_TIME(
|
|
&my_time, (my_time_t) time);
|
|
#else
|
|
localtime_r(&time, &tm_time);
|
|
localtime_to_TIME(&my_time, &tm_time);
|
|
my_time.time_type = MYSQL_TIMESTAMP_DATETIME;
|
|
#endif
|
|
} else {
|
|
memset(&my_time, 0, sizeof(my_time));
|
|
}
|
|
|
|
/* JAN: TODO: MySQL 5.7
|
|
return(field->store_time(&my_time, MYSQL_TIMESTAMP_DATETIME));
|
|
*/
|
|
return(field->store_time(&my_time));
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Auxiliary function to store char* value in MYSQL_TYPE_STRING field.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
field_store_string(
|
|
/*===============*/
|
|
Field* field, /*!< in/out: target field for storage */
|
|
const char* str) /*!< in: NUL-terminated utf-8 string,
|
|
or NULL */
|
|
{
|
|
if (!str) {
|
|
field->set_null();
|
|
return 0;
|
|
}
|
|
|
|
field->set_notnull();
|
|
return field->store(str, uint(strlen(str)), system_charset_info);
|
|
}
|
|
|
|
#ifdef BTR_CUR_HASH_ADAPT
|
|
# define I_S_AHI 1 /* Include the IS_HASHED column */
|
|
#else
|
|
# define I_S_AHI 0 /* Omit the IS_HASHED column */
|
|
#endif
|
|
|
|
static const LEX_CSTRING isolation_level_values[] =
|
|
{
|
|
{ STRING_WITH_LEN("READ UNCOMMITTED") },
|
|
{ STRING_WITH_LEN("READ COMMITTED") },
|
|
{ STRING_WITH_LEN("REPEATABLE READ") },
|
|
{ STRING_WITH_LEN("SERIALIZABLE") }
|
|
};
|
|
|
|
static TypelibBuffer<4> isolation_level_values_typelib(isolation_level_values);
|
|
|
|
namespace Show {
|
|
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_trx */
|
|
static ST_FIELD_INFO innodb_trx_fields_info[]=
|
|
{
|
|
#define IDX_TRX_ID 0
|
|
Column("trx_id", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_TRX_STATE 1
|
|
Column("trx_state", Varchar(13), NOT_NULL),
|
|
|
|
#define IDX_TRX_STARTED 2
|
|
Column("trx_started", Datetime(0), NOT_NULL),
|
|
|
|
#define IDX_TRX_REQUESTED_LOCK_ID 3
|
|
Column("trx_requested_lock_id",
|
|
Varchar(TRX_I_S_LOCK_ID_MAX_LEN + 1), NULLABLE),
|
|
|
|
#define IDX_TRX_WAIT_STARTED 4
|
|
Column("trx_wait_started", Datetime(0), NULLABLE),
|
|
|
|
#define IDX_TRX_WEIGHT 5
|
|
Column("trx_weight", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_TRX_MYSQL_THREAD_ID 6
|
|
Column("trx_mysql_thread_id", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_TRX_QUERY 7
|
|
Column("trx_query", Varchar(TRX_I_S_TRX_QUERY_MAX_LEN), NULLABLE),
|
|
|
|
#define IDX_TRX_OPERATION_STATE 8
|
|
Column("trx_operation_state", Varchar(64), NULLABLE),
|
|
|
|
#define IDX_TRX_TABLES_IN_USE 9
|
|
Column("trx_tables_in_use", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_TRX_TABLES_LOCKED 10
|
|
Column("trx_tables_locked", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_TRX_LOCK_STRUCTS 11
|
|
Column("trx_lock_structs", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_TRX_LOCK_MEMORY_BYTES 12
|
|
Column("trx_lock_memory_bytes", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_TRX_ROWS_LOCKED 13
|
|
Column("trx_rows_locked", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_TRX_ROWS_MODIFIED 14
|
|
Column("trx_rows_modified", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_TRX_CONNCURRENCY_TICKETS 15
|
|
Column("trx_concurrency_tickets", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_TRX_ISOLATION_LEVEL 16
|
|
Column("trx_isolation_level",
|
|
Enum(&isolation_level_values_typelib), NOT_NULL),
|
|
|
|
#define IDX_TRX_UNIQUE_CHECKS 17
|
|
Column("trx_unique_checks", SLong(1), NOT_NULL),
|
|
|
|
#define IDX_TRX_FOREIGN_KEY_CHECKS 18
|
|
Column("trx_foreign_key_checks", SLong(1), NOT_NULL),
|
|
|
|
#define IDX_TRX_LAST_FOREIGN_KEY_ERROR 19
|
|
Column("trx_last_foreign_key_error",
|
|
Varchar(TRX_I_S_TRX_FK_ERROR_MAX_LEN),NULLABLE),
|
|
|
|
#define IDX_TRX_READ_ONLY 20
|
|
Column("trx_is_read_only", SLong(1), NOT_NULL),
|
|
|
|
#define IDX_TRX_AUTOCOMMIT_NON_LOCKING 21
|
|
Column("trx_autocommit_non_locking", SLong(1), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
|
|
} // namespace Show
|
|
|
|
/*******************************************************************//**
|
|
Read data from cache buffer and fill the INFORMATION_SCHEMA.innodb_trx
|
|
table with it.
|
|
@retval 0 on success
|
|
@retval 1 on failure */
|
|
static int fill_innodb_trx_from_cache(THD *thd, TABLE_LIST *tables, Item*)
|
|
{
|
|
ulint rows_num;
|
|
char lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
|
|
ulint i;
|
|
|
|
DBUG_ENTER("fill_innodb_trx_from_cache");
|
|
|
|
if (!trx_i_s_common_fill_table(thd, tables)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct cache
|
|
{
|
|
cache() { trx_i_s_cache_start_read(trx_i_s_cache); }
|
|
~cache() { trx_i_s_cache_end_read(trx_i_s_cache); }
|
|
} c;
|
|
|
|
Field** fields = tables->table->field;
|
|
|
|
rows_num = trx_i_s_cache_get_rows_used(trx_i_s_cache,
|
|
I_S_INNODB_TRX);
|
|
|
|
for (i = 0; i < rows_num; i++) {
|
|
|
|
i_s_trx_row_t* row;
|
|
|
|
row = (i_s_trx_row_t*)
|
|
trx_i_s_cache_get_nth_row(
|
|
trx_i_s_cache, I_S_INNODB_TRX, i);
|
|
|
|
/* trx_id */
|
|
OK(fields[IDX_TRX_ID]->store(row->trx_id, true));
|
|
|
|
/* trx_state */
|
|
OK(field_store_string(fields[IDX_TRX_STATE],
|
|
row->trx_state));
|
|
|
|
/* trx_started */
|
|
OK(field_store_time_t(fields[IDX_TRX_STARTED],
|
|
(time_t) row->trx_started));
|
|
|
|
/* trx_requested_lock_id */
|
|
/* trx_wait_started */
|
|
if (row->trx_wait_started != 0) {
|
|
|
|
OK(field_store_string(
|
|
fields[IDX_TRX_REQUESTED_LOCK_ID],
|
|
trx_i_s_create_lock_id(
|
|
row->requested_lock_row,
|
|
lock_id, sizeof(lock_id))));
|
|
/* field_store_string() sets it no notnull */
|
|
|
|
OK(field_store_time_t(
|
|
fields[IDX_TRX_WAIT_STARTED],
|
|
(time_t) row->trx_wait_started));
|
|
fields[IDX_TRX_WAIT_STARTED]->set_notnull();
|
|
} else {
|
|
|
|
fields[IDX_TRX_REQUESTED_LOCK_ID]->set_null();
|
|
fields[IDX_TRX_WAIT_STARTED]->set_null();
|
|
}
|
|
|
|
/* trx_weight */
|
|
OK(fields[IDX_TRX_WEIGHT]->store(row->trx_weight, true));
|
|
|
|
/* trx_mysql_thread_id */
|
|
OK(fields[IDX_TRX_MYSQL_THREAD_ID]->store(
|
|
row->trx_mysql_thread_id, true));
|
|
|
|
/* trx_query */
|
|
if (row->trx_query) {
|
|
/* store will do appropriate character set
|
|
conversion check */
|
|
fields[IDX_TRX_QUERY]->store(
|
|
row->trx_query,
|
|
static_cast<uint>(strlen(row->trx_query)),
|
|
row->trx_query_cs);
|
|
fields[IDX_TRX_QUERY]->set_notnull();
|
|
} else {
|
|
fields[IDX_TRX_QUERY]->set_null();
|
|
}
|
|
|
|
/* trx_operation_state */
|
|
OK(field_store_string(fields[IDX_TRX_OPERATION_STATE],
|
|
row->trx_operation_state));
|
|
|
|
/* trx_tables_in_use */
|
|
OK(fields[IDX_TRX_TABLES_IN_USE]->store(
|
|
row->trx_tables_in_use, true));
|
|
|
|
/* trx_tables_locked */
|
|
OK(fields[IDX_TRX_TABLES_LOCKED]->store(
|
|
row->trx_tables_locked, true));
|
|
|
|
/* trx_lock_structs */
|
|
OK(fields[IDX_TRX_LOCK_STRUCTS]->store(
|
|
row->trx_lock_structs, true));
|
|
|
|
/* trx_lock_memory_bytes */
|
|
OK(fields[IDX_TRX_LOCK_MEMORY_BYTES]->store(
|
|
row->trx_lock_memory_bytes, true));
|
|
|
|
/* trx_rows_locked */
|
|
OK(fields[IDX_TRX_ROWS_LOCKED]->store(
|
|
row->trx_rows_locked, true));
|
|
|
|
/* trx_rows_modified */
|
|
OK(fields[IDX_TRX_ROWS_MODIFIED]->store(
|
|
row->trx_rows_modified, true));
|
|
|
|
/* trx_concurrency_tickets */
|
|
OK(fields[IDX_TRX_CONNCURRENCY_TICKETS]->store(0, true));
|
|
|
|
/* trx_isolation_level */
|
|
OK(fields[IDX_TRX_ISOLATION_LEVEL]->store(
|
|
1 + row->trx_isolation_level, true));
|
|
|
|
/* trx_unique_checks */
|
|
OK(fields[IDX_TRX_UNIQUE_CHECKS]->store(
|
|
row->trx_unique_checks, true));
|
|
|
|
/* trx_foreign_key_checks */
|
|
OK(fields[IDX_TRX_FOREIGN_KEY_CHECKS]->store(
|
|
row->trx_foreign_key_checks, true));
|
|
|
|
/* trx_last_foreign_key_error */
|
|
OK(field_store_string(fields[IDX_TRX_LAST_FOREIGN_KEY_ERROR],
|
|
row->trx_foreign_key_error));
|
|
|
|
/* trx_is_read_only*/
|
|
OK(fields[IDX_TRX_READ_ONLY]->store(
|
|
row->trx_is_read_only, true));
|
|
|
|
/* trx_is_autocommit_non_locking */
|
|
OK(fields[IDX_TRX_AUTOCOMMIT_NON_LOCKING]->store(
|
|
row->trx_is_autocommit_non_locking, true));
|
|
|
|
OK(schema_table_store_record(thd, tables->table));
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.innodb_trx
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
innodb_trx_init(
|
|
/*============*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("innodb_trx_init");
|
|
|
|
schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::innodb_trx_fields_info;
|
|
schema->fill_table = fill_innodb_trx_from_cache;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
static struct st_mysql_information_schema i_s_info =
|
|
{
|
|
MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
|
|
};
|
|
|
|
/** version number reported by SHOW PLUGINS */
|
|
constexpr unsigned i_s_version= MYSQL_VERSION_MAJOR << 8 | MYSQL_VERSION_MINOR;
|
|
|
|
struct st_maria_plugin i_s_innodb_trx =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_TRX",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB transactions",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
innodb_trx_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
static const LEX_CSTRING lock_mode_values[] =
|
|
{
|
|
{ STRING_WITH_LEN("S") },
|
|
{ STRING_WITH_LEN("S,GAP") },
|
|
{ STRING_WITH_LEN("X") },
|
|
{ STRING_WITH_LEN("X,GAP") },
|
|
{ STRING_WITH_LEN("IS") },
|
|
{ STRING_WITH_LEN("IS,GAP") },
|
|
{ STRING_WITH_LEN("IX") },
|
|
{ STRING_WITH_LEN("IX,GAP") },
|
|
{ STRING_WITH_LEN("AUTO_INC") }
|
|
};
|
|
|
|
static TypelibBuffer<9> lock_mode_values_typelib(lock_mode_values);
|
|
|
|
static const LEX_CSTRING lock_type_values[] =
|
|
{
|
|
{ STRING_WITH_LEN("RECORD") },
|
|
{ STRING_WITH_LEN("TABLE") }
|
|
};
|
|
|
|
static TypelibBuffer<2> lock_type_values_typelib(lock_type_values);
|
|
|
|
namespace Show {
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_locks */
|
|
static ST_FIELD_INFO innodb_locks_fields_info[]=
|
|
{
|
|
#define IDX_LOCK_ID 0
|
|
Column("lock_id", Varchar(TRX_I_S_LOCK_ID_MAX_LEN + 1), NOT_NULL),
|
|
|
|
#define IDX_LOCK_TRX_ID 1
|
|
Column("lock_trx_id", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_LOCK_MODE 2
|
|
Column("lock_mode", Enum(&lock_mode_values_typelib), NOT_NULL),
|
|
|
|
#define IDX_LOCK_TYPE 3
|
|
Column("lock_type", Enum(&lock_type_values_typelib), NOT_NULL),
|
|
|
|
#define IDX_LOCK_TABLE 4
|
|
Column("lock_table", Varchar(1024), NOT_NULL),
|
|
|
|
#define IDX_LOCK_INDEX 5
|
|
Column("lock_index", Varchar(1024), NULLABLE),
|
|
|
|
#define IDX_LOCK_SPACE 6
|
|
Column("lock_space", ULong(), NULLABLE),
|
|
|
|
#define IDX_LOCK_PAGE 7
|
|
Column("lock_page", ULong(), NULLABLE),
|
|
|
|
#define IDX_LOCK_REC 8
|
|
Column("lock_rec", ULong(), NULLABLE),
|
|
|
|
#define IDX_LOCK_DATA 9
|
|
Column("lock_data", Varchar(TRX_I_S_LOCK_DATA_MAX_LEN), NULLABLE),
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/*******************************************************************//**
|
|
Read data from cache buffer and fill the INFORMATION_SCHEMA.innodb_locks
|
|
table with it.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
fill_innodb_locks_from_cache(
|
|
/*=========================*/
|
|
THD* thd, /*!< in: MySQL client connection */
|
|
TABLE_LIST* tables, /*!< in/out: fill this table */
|
|
Item*)
|
|
{
|
|
ulint rows_num;
|
|
char lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
|
|
ulint i;
|
|
|
|
DBUG_ENTER("fill_innodb_locks_from_cache");
|
|
|
|
if (!trx_i_s_common_fill_table(thd, tables)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct cache
|
|
{
|
|
cache() { trx_i_s_cache_start_read(trx_i_s_cache); }
|
|
~cache() { trx_i_s_cache_end_read(trx_i_s_cache); }
|
|
} c;
|
|
|
|
Field** fields = tables->table->field;
|
|
|
|
rows_num = trx_i_s_cache_get_rows_used(trx_i_s_cache,
|
|
I_S_INNODB_LOCKS);
|
|
|
|
for (i = 0; i < rows_num; i++) {
|
|
|
|
i_s_locks_row_t* row;
|
|
char buf[MAX_FULL_NAME_LEN + 1];
|
|
const char* bufend;
|
|
|
|
row = (i_s_locks_row_t*)
|
|
trx_i_s_cache_get_nth_row(
|
|
trx_i_s_cache, I_S_INNODB_LOCKS, i);
|
|
|
|
/* lock_id */
|
|
trx_i_s_create_lock_id(row, lock_id, sizeof(lock_id));
|
|
OK(field_store_string(fields[IDX_LOCK_ID],
|
|
lock_id));
|
|
|
|
/* lock_trx_id */
|
|
OK(fields[IDX_LOCK_TRX_ID]->store(row->lock_trx_id, true));
|
|
|
|
/* lock_mode */
|
|
OK(fields[IDX_LOCK_MODE]->store(row->lock_mode, true));
|
|
|
|
/* lock_type */
|
|
OK(fields[IDX_LOCK_TYPE]->store(
|
|
row->lock_index ? 1 : 2, true));
|
|
|
|
/* lock_table */
|
|
bufend = innobase_convert_name(buf, sizeof(buf),
|
|
row->lock_table,
|
|
strlen(row->lock_table),
|
|
thd);
|
|
OK(fields[IDX_LOCK_TABLE]->store(
|
|
buf, uint(bufend - buf), system_charset_info));
|
|
|
|
if (row->lock_index) {
|
|
/* record lock */
|
|
OK(field_store_string(fields[IDX_LOCK_INDEX],
|
|
row->lock_index));
|
|
OK(fields[IDX_LOCK_SPACE]->store(
|
|
row->lock_page.space(), true));
|
|
fields[IDX_LOCK_SPACE]->set_notnull();
|
|
OK(fields[IDX_LOCK_PAGE]->store(
|
|
row->lock_page.page_no(), true));
|
|
fields[IDX_LOCK_PAGE]->set_notnull();
|
|
OK(fields[IDX_LOCK_REC]->store(
|
|
row->lock_rec, true));
|
|
fields[IDX_LOCK_REC]->set_notnull();
|
|
OK(field_store_string(fields[IDX_LOCK_DATA],
|
|
row->lock_data));
|
|
} else {
|
|
fields[IDX_LOCK_INDEX]->set_null();
|
|
fields[IDX_LOCK_SPACE]->set_null();
|
|
fields[IDX_LOCK_REC]->set_null();
|
|
fields[IDX_LOCK_DATA]->set_null();
|
|
}
|
|
|
|
OK(schema_table_store_record(thd, tables->table));
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.innodb_locks
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
innodb_locks_init(
|
|
/*==============*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("innodb_locks_init");
|
|
|
|
schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::innodb_locks_fields_info;
|
|
schema->fill_table = fill_innodb_locks_from_cache;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_locks =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_LOCKS",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB conflicting locks",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
innodb_locks_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
|
|
namespace Show {
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_lock_waits */
|
|
static ST_FIELD_INFO innodb_lock_waits_fields_info[]=
|
|
{
|
|
#define IDX_REQUESTING_TRX_ID 0
|
|
Column("requesting_trx_id", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_REQUESTED_LOCK_ID 1
|
|
Column("requested_lock_id", Varchar(TRX_I_S_LOCK_ID_MAX_LEN + 1), NOT_NULL),
|
|
|
|
#define IDX_BLOCKING_TRX_ID 2
|
|
Column("blocking_trx_id", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BLOCKING_LOCK_ID 3
|
|
Column("blocking_lock_id", Varchar(TRX_I_S_LOCK_ID_MAX_LEN + 1), NOT_NULL),
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/*******************************************************************//**
|
|
Read data from cache buffer and fill the
|
|
INFORMATION_SCHEMA.innodb_lock_waits table with it.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
fill_innodb_lock_waits_from_cache(
|
|
/*==============================*/
|
|
THD* thd, /*!< in: used to call
|
|
schema_table_store_record() */
|
|
TABLE_LIST* tables, /*!< in/out: fill this table */
|
|
Item*)
|
|
{
|
|
ulint rows_num;
|
|
char requested_lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
|
|
char blocking_lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
|
|
ulint i;
|
|
|
|
DBUG_ENTER("fill_innodb_lock_waits_from_cache");
|
|
|
|
if (!trx_i_s_common_fill_table(thd, tables)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct cache
|
|
{
|
|
cache() { trx_i_s_cache_start_read(trx_i_s_cache); }
|
|
~cache() { trx_i_s_cache_end_read(trx_i_s_cache); }
|
|
} c;
|
|
|
|
Field** fields = tables->table->field;
|
|
|
|
rows_num = trx_i_s_cache_get_rows_used(trx_i_s_cache,
|
|
I_S_INNODB_LOCK_WAITS);
|
|
|
|
for (i = 0; i < rows_num; i++) {
|
|
|
|
i_s_lock_waits_row_t* row;
|
|
|
|
row = (i_s_lock_waits_row_t*)
|
|
trx_i_s_cache_get_nth_row(
|
|
trx_i_s_cache, I_S_INNODB_LOCK_WAITS, i);
|
|
|
|
/* requesting_trx_id */
|
|
OK(fields[IDX_REQUESTING_TRX_ID]->store(
|
|
row->requested_lock_row->lock_trx_id, true));
|
|
|
|
/* requested_lock_id */
|
|
OK(field_store_string(
|
|
fields[IDX_REQUESTED_LOCK_ID],
|
|
trx_i_s_create_lock_id(
|
|
row->requested_lock_row,
|
|
requested_lock_id,
|
|
sizeof(requested_lock_id))));
|
|
|
|
/* blocking_trx_id */
|
|
OK(fields[IDX_BLOCKING_TRX_ID]->store(
|
|
row->blocking_lock_row->lock_trx_id, true));
|
|
|
|
/* blocking_lock_id */
|
|
OK(field_store_string(
|
|
fields[IDX_BLOCKING_LOCK_ID],
|
|
trx_i_s_create_lock_id(
|
|
row->blocking_lock_row,
|
|
blocking_lock_id,
|
|
sizeof(blocking_lock_id))));
|
|
|
|
OK(schema_table_store_record(thd, tables->table));
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.innodb_lock_waits
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
innodb_lock_waits_init(
|
|
/*===================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("innodb_lock_waits_init");
|
|
|
|
schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::innodb_lock_waits_fields_info;
|
|
schema->fill_table = fill_innodb_lock_waits_from_cache;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_lock_waits =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_LOCK_WAITS",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB which lock is blocking which",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
innodb_lock_waits_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
namespace Show {
|
|
/* Fields of the dynamic table information_schema.innodb_cmp. */
|
|
static ST_FIELD_INFO i_s_cmp_fields_info[] =
|
|
{
|
|
Column("page_size", SLong(5),NOT_NULL, "Compressed Page Size"),
|
|
Column("compress_ops", SLong(), NOT_NULL, "Total Number of Compressions"),
|
|
Column("compress_ops_ok",SLong(), NOT_NULL, "Total Number of "
|
|
"Successful Compressions"),
|
|
Column("compress_time", SLong(), NOT_NULL, "Total Duration of "
|
|
"Compressions, in Seconds"),
|
|
Column("uncompress_ops", SLong(), NOT_NULL, "Total Number of Decompressions"),
|
|
Column("uncompress_time",SLong(), NOT_NULL, "Total Duration of "
|
|
"Decompressions, in Seconds"),
|
|
CEnd(),
|
|
};
|
|
} // namespace Show
|
|
|
|
|
|
/*******************************************************************//**
|
|
Fill the dynamic table information_schema.innodb_cmp or
|
|
innodb_cmp_reset.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_cmp_fill_low(
|
|
/*=============*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* , /*!< in: condition (ignored) */
|
|
ibool reset) /*!< in: TRUE=reset cumulated counts */
|
|
{
|
|
TABLE* table = (TABLE*) tables->table;
|
|
int status = 0;
|
|
|
|
DBUG_ENTER("i_s_cmp_fill_low");
|
|
|
|
/* deny access to non-superusers */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
for (uint i = 0; i < PAGE_ZIP_SSIZE_MAX; i++) {
|
|
page_zip_stat_t* zip_stat = &page_zip_stat[i];
|
|
|
|
table->field[0]->store(UNIV_ZIP_SIZE_MIN << i);
|
|
|
|
/* The cumulated counts are not protected by any
|
|
mutex. Thus, some operation in page0zip.cc could
|
|
increment a counter between the time we read it and
|
|
clear it. We could introduce mutex protection, but it
|
|
could cause a measureable performance hit in
|
|
page0zip.cc. */
|
|
table->field[1]->store(zip_stat->compressed, true);
|
|
table->field[2]->store(zip_stat->compressed_ok, true);
|
|
table->field[3]->store(zip_stat->compressed_usec / 1000000,
|
|
true);
|
|
table->field[4]->store(zip_stat->decompressed, true);
|
|
table->field[5]->store(zip_stat->decompressed_usec / 1000000,
|
|
true);
|
|
|
|
if (reset) {
|
|
new (zip_stat) page_zip_stat_t();
|
|
}
|
|
|
|
if (schema_table_store_record(thd, table)) {
|
|
status = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
DBUG_RETURN(status);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Fill the dynamic table information_schema.innodb_cmp.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_cmp_fill(
|
|
/*=========*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* cond) /*!< in: condition (ignored) */
|
|
{
|
|
return(i_s_cmp_fill_low(thd, tables, cond, FALSE));
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Fill the dynamic table information_schema.innodb_cmp_reset.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_cmp_reset_fill(
|
|
/*===============*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* cond) /*!< in: condition (ignored) */
|
|
{
|
|
return(i_s_cmp_fill_low(thd, tables, cond, TRUE));
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table information_schema.innodb_cmp.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_cmp_init(
|
|
/*=========*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
DBUG_ENTER("i_s_cmp_init");
|
|
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::i_s_cmp_fields_info;
|
|
schema->fill_table = i_s_cmp_fill;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table information_schema.innodb_cmp_reset.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_cmp_reset_init(
|
|
/*===============*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
DBUG_ENTER("i_s_cmp_reset_init");
|
|
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::i_s_cmp_fields_info;
|
|
schema->fill_table = i_s_cmp_reset_fill;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_cmp =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_CMP",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"Statistics for the InnoDB compression",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_cmp_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
struct st_maria_plugin i_s_innodb_cmp_reset =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_CMP_RESET",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"Statistics for the InnoDB compression;"
|
|
" reset cumulated counts",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_cmp_reset_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
|
|
namespace Show {
|
|
/* Fields of the dynamic tables
|
|
information_schema.innodb_cmp_per_index and
|
|
information_schema.innodb_cmp_per_index_reset. */
|
|
static ST_FIELD_INFO i_s_cmp_per_index_fields_info[]=
|
|
{
|
|
#define IDX_DATABASE_NAME 0
|
|
Column("database_name", Varchar(NAME_CHAR_LEN), NOT_NULL),
|
|
|
|
#define IDX_TABLE_NAME 1 /* FIXME: this is in my_charset_filename! */
|
|
Column("table_name", Varchar(NAME_CHAR_LEN), NOT_NULL),
|
|
|
|
#define IDX_INDEX_NAME 2
|
|
Column("index_name", Varchar(NAME_CHAR_LEN), NOT_NULL),
|
|
|
|
#define IDX_COMPRESS_OPS 3
|
|
Column("compress_ops", SLong(), NOT_NULL),
|
|
|
|
#define IDX_COMPRESS_OPS_OK 4
|
|
Column("compress_ops_ok", SLong(), NOT_NULL),
|
|
|
|
#define IDX_COMPRESS_TIME 5
|
|
Column("compress_time", SLong(), NOT_NULL),
|
|
|
|
#define IDX_UNCOMPRESS_OPS 6
|
|
Column("uncompress_ops", SLong(), NOT_NULL),
|
|
|
|
#define IDX_UNCOMPRESS_TIME 7
|
|
Column("uncompress_time", SLong(), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
|
|
} // namespace Show
|
|
|
|
/*******************************************************************//**
|
|
Fill the dynamic table
|
|
information_schema.innodb_cmp_per_index or
|
|
information_schema.innodb_cmp_per_index_reset.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_cmp_per_index_fill_low(
|
|
/*=======================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* , /*!< in: condition (ignored) */
|
|
ibool reset) /*!< in: TRUE=reset cumulated counts */
|
|
{
|
|
TABLE* table = tables->table;
|
|
Field** fields = table->field;
|
|
int status = 0;
|
|
|
|
DBUG_ENTER("i_s_cmp_per_index_fill_low");
|
|
|
|
/* deny access to non-superusers */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
/* Create a snapshot of the stats so we do not bump into lock
|
|
order violations with dict_sys.latch below. */
|
|
mysql_mutex_lock(&page_zip_stat_per_index_mutex);
|
|
page_zip_stat_per_index_t snap (page_zip_stat_per_index);
|
|
mysql_mutex_unlock(&page_zip_stat_per_index_mutex);
|
|
|
|
dict_sys.freeze(SRW_LOCK_CALL);
|
|
|
|
page_zip_stat_per_index_t::iterator iter;
|
|
ulint i;
|
|
|
|
for (iter = snap.begin(), i = 0; iter != snap.end(); iter++, i++) {
|
|
|
|
if (dict_index_t* index
|
|
= dict_index_get_if_in_cache_low(iter->first)) {
|
|
char db_utf8[MAX_DB_UTF8_LEN];
|
|
char table_utf8[MAX_TABLE_UTF8_LEN];
|
|
|
|
dict_fs2utf8(index->table->name.m_name,
|
|
db_utf8, sizeof(db_utf8),
|
|
table_utf8, sizeof(table_utf8));
|
|
|
|
status = field_store_string(fields[IDX_DATABASE_NAME],
|
|
db_utf8)
|
|
|| field_store_string(fields[IDX_TABLE_NAME],
|
|
table_utf8)
|
|
|| field_store_string(fields[IDX_INDEX_NAME],
|
|
index->name);
|
|
} else {
|
|
/* index not found */
|
|
char name[MY_INT64_NUM_DECIMAL_DIGITS
|
|
+ sizeof "index_id: "];
|
|
fields[IDX_DATABASE_NAME]->set_null();
|
|
fields[IDX_TABLE_NAME]->set_null();
|
|
fields[IDX_INDEX_NAME]->set_notnull();
|
|
status = fields[IDX_INDEX_NAME]->store(
|
|
name,
|
|
uint(snprintf(name, sizeof name,
|
|
"index_id: " IB_ID_FMT,
|
|
iter->first)),
|
|
system_charset_info);
|
|
}
|
|
|
|
if (status
|
|
|| fields[IDX_COMPRESS_OPS]->store(
|
|
iter->second.compressed, true)
|
|
|| fields[IDX_COMPRESS_OPS_OK]->store(
|
|
iter->second.compressed_ok, true)
|
|
|| fields[IDX_COMPRESS_TIME]->store(
|
|
iter->second.compressed_usec / 1000000, true)
|
|
|| fields[IDX_UNCOMPRESS_OPS]->store(
|
|
iter->second.decompressed, true)
|
|
|| fields[IDX_UNCOMPRESS_TIME]->store(
|
|
iter->second.decompressed_usec / 1000000, true)
|
|
|| schema_table_store_record(thd, table)) {
|
|
status = 1;
|
|
break;
|
|
}
|
|
/* Release and reacquire the dict_sys.latch to allow other
|
|
threads to proceed. This could eventually result in the
|
|
contents of INFORMATION_SCHEMA.innodb_cmp_per_index being
|
|
inconsistent, but it is an acceptable compromise. */
|
|
if (i == 1000) {
|
|
dict_sys.unfreeze();
|
|
i = 0;
|
|
dict_sys.freeze(SRW_LOCK_CALL);
|
|
}
|
|
}
|
|
|
|
dict_sys.unfreeze();
|
|
|
|
if (reset) {
|
|
page_zip_reset_stat_per_index();
|
|
}
|
|
|
|
DBUG_RETURN(status);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Fill the dynamic table information_schema.innodb_cmp_per_index.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_cmp_per_index_fill(
|
|
/*===================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* cond) /*!< in: condition (ignored) */
|
|
{
|
|
return(i_s_cmp_per_index_fill_low(thd, tables, cond, FALSE));
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Fill the dynamic table information_schema.innodb_cmp_per_index_reset.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_cmp_per_index_reset_fill(
|
|
/*=========================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* cond) /*!< in: condition (ignored) */
|
|
{
|
|
return(i_s_cmp_per_index_fill_low(thd, tables, cond, TRUE));
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table information_schema.innodb_cmp_per_index.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_cmp_per_index_init(
|
|
/*===================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
DBUG_ENTER("i_s_cmp_init");
|
|
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::i_s_cmp_per_index_fields_info;
|
|
schema->fill_table = i_s_cmp_per_index_fill;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table information_schema.innodb_cmp_per_index_reset.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_cmp_per_index_reset_init(
|
|
/*=========================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
DBUG_ENTER("i_s_cmp_reset_init");
|
|
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::i_s_cmp_per_index_fields_info;
|
|
schema->fill_table = i_s_cmp_per_index_reset_fill;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_cmp_per_index =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_CMP_PER_INDEX",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"Statistics for the InnoDB compression (per index)",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_cmp_per_index_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
struct st_maria_plugin i_s_innodb_cmp_per_index_reset =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_CMP_PER_INDEX_RESET",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"Statistics for the InnoDB compression (per index);"
|
|
" reset cumulated counts",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_cmp_per_index_reset_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
|
|
namespace Show {
|
|
/* Fields of the dynamic table information_schema.innodb_cmpmem. */
|
|
static ST_FIELD_INFO i_s_cmpmem_fields_info[] =
|
|
{
|
|
Column("page_size", SLong(5), NOT_NULL, "Buddy Block Size"),
|
|
Column("buffer_pool_instance", SLong(), NOT_NULL, "Buffer Pool Id"),
|
|
Column("pages_used", SLong(), NOT_NULL, "Currently in Use"),
|
|
Column("pages_free", SLong(), NOT_NULL, "Currently Available"),
|
|
Column("relocation_ops", SLonglong(), NOT_NULL, "Total Number of Relocations"),
|
|
Column("relocation_time", SLong(), NOT_NULL, "Total Duration of Relocations,"
|
|
" in Seconds"),
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/*******************************************************************//**
|
|
Fill the dynamic table information_schema.innodb_cmpmem or
|
|
innodb_cmpmem_reset.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_cmpmem_fill_low(
|
|
/*================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* , /*!< in: condition (ignored) */
|
|
ibool reset) /*!< in: TRUE=reset cumulated counts */
|
|
{
|
|
TABLE* table = (TABLE*) tables->table;
|
|
|
|
DBUG_ENTER("i_s_cmpmem_fill_low");
|
|
|
|
/* deny access to non-superusers */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
ulint zip_free_len_local[BUF_BUDDY_SIZES_MAX + 1];
|
|
buf_buddy_stat_t buddy_stat_local[BUF_BUDDY_SIZES_MAX + 1];
|
|
|
|
/* Save buddy stats for buffer pool in local variables. */
|
|
mysql_mutex_lock(&buf_pool.mutex);
|
|
|
|
for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) {
|
|
zip_free_len_local[x] = (x < BUF_BUDDY_SIZES) ?
|
|
UT_LIST_GET_LEN(buf_pool.zip_free[x]) : 0;
|
|
|
|
buddy_stat_local[x] = buf_pool.buddy_stat[x];
|
|
|
|
if (reset) {
|
|
/* This is protected by buf_pool.mutex. */
|
|
buf_pool.buddy_stat[x].relocated = 0;
|
|
buf_pool.buddy_stat[x].relocated_usec = 0;
|
|
}
|
|
}
|
|
|
|
mysql_mutex_unlock(&buf_pool.mutex);
|
|
|
|
for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) {
|
|
buf_buddy_stat_t* buddy_stat = &buddy_stat_local[x];
|
|
|
|
Field **field = table->field;
|
|
|
|
(*field++)->store(BUF_BUDDY_LOW << x);
|
|
(*field++)->store(0, true);
|
|
(*field++)->store(buddy_stat->used, true);
|
|
(*field++)->store(zip_free_len_local[x], true);
|
|
(*field++)->store(buddy_stat->relocated, true);
|
|
(*field)->store(buddy_stat->relocated_usec / 1000000, true);
|
|
|
|
if (schema_table_store_record(thd, table)) {
|
|
DBUG_RETURN(1);
|
|
}
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Fill the dynamic table information_schema.innodb_cmpmem.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_cmpmem_fill(
|
|
/*============*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* cond) /*!< in: condition (ignored) */
|
|
{
|
|
return(i_s_cmpmem_fill_low(thd, tables, cond, FALSE));
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Fill the dynamic table information_schema.innodb_cmpmem_reset.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_cmpmem_reset_fill(
|
|
/*==================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* cond) /*!< in: condition (ignored) */
|
|
{
|
|
return(i_s_cmpmem_fill_low(thd, tables, cond, TRUE));
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table information_schema.innodb_cmpmem.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_cmpmem_init(
|
|
/*============*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
DBUG_ENTER("i_s_cmpmem_init");
|
|
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::i_s_cmpmem_fields_info;
|
|
schema->fill_table = i_s_cmpmem_fill;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table information_schema.innodb_cmpmem_reset.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_cmpmem_reset_init(
|
|
/*==================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
DBUG_ENTER("i_s_cmpmem_reset_init");
|
|
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::i_s_cmpmem_fields_info;
|
|
schema->fill_table = i_s_cmpmem_reset_fill;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_cmpmem =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_CMPMEM",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"Statistics for the InnoDB compressed buffer pool",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_cmpmem_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
struct st_maria_plugin i_s_innodb_cmpmem_reset =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_CMPMEM_RESET",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"Statistics for the InnoDB compressed buffer pool;"
|
|
" reset cumulated counts",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_cmpmem_reset_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
|
|
static const LEX_CSTRING metric_type_values[] =
|
|
{
|
|
{ STRING_WITH_LEN("value") },
|
|
{ STRING_WITH_LEN("status_counter") },
|
|
{ STRING_WITH_LEN("set_owner") },
|
|
{ STRING_WITH_LEN("set_member") },
|
|
{ STRING_WITH_LEN("counter") }
|
|
};
|
|
|
|
static TypelibBuffer<5> metric_type_values_typelib(metric_type_values);
|
|
|
|
namespace Show {
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_metrics */
|
|
static ST_FIELD_INFO innodb_metrics_fields_info[]=
|
|
{
|
|
#define METRIC_NAME 0
|
|
Column("NAME", Varchar(NAME_LEN + 1), NOT_NULL),
|
|
|
|
#define METRIC_SUBSYS 1
|
|
Column("SUBSYSTEM", Varchar(NAME_LEN + 1), NOT_NULL),
|
|
|
|
#define METRIC_VALUE_START 2
|
|
Column("COUNT", SLonglong(), NOT_NULL),
|
|
|
|
#define METRIC_MAX_VALUE_START 3
|
|
Column("MAX_COUNT", SLonglong(), NULLABLE),
|
|
|
|
#define METRIC_MIN_VALUE_START 4
|
|
Column("MIN_COUNT", SLonglong(), NULLABLE),
|
|
|
|
#define METRIC_AVG_VALUE_START 5
|
|
Column("AVG_COUNT", Float(MAX_FLOAT_STR_LENGTH), NULLABLE),
|
|
|
|
#define METRIC_VALUE_RESET 6
|
|
Column("COUNT_RESET", SLonglong(), NOT_NULL),
|
|
|
|
#define METRIC_MAX_VALUE_RESET 7
|
|
Column("MAX_COUNT_RESET", SLonglong(), NULLABLE),
|
|
|
|
#define METRIC_MIN_VALUE_RESET 8
|
|
Column("MIN_COUNT_RESET", SLonglong(), NULLABLE),
|
|
|
|
#define METRIC_AVG_VALUE_RESET 9
|
|
Column("AVG_COUNT_RESET", Float(MAX_FLOAT_STR_LENGTH), NULLABLE),
|
|
|
|
#define METRIC_START_TIME 10
|
|
Column("TIME_ENABLED", Datetime(0), NULLABLE),
|
|
|
|
#define METRIC_STOP_TIME 11
|
|
Column("TIME_DISABLED", Datetime(0), NULLABLE),
|
|
|
|
#define METRIC_TIME_ELAPSED 12
|
|
Column("TIME_ELAPSED", SLonglong(), NULLABLE),
|
|
|
|
#define METRIC_RESET_TIME 13
|
|
Column("TIME_RESET", Datetime(0), NULLABLE),
|
|
|
|
#define METRIC_STATUS 14
|
|
Column("ENABLED", SLong(1), NOT_NULL),
|
|
|
|
#define METRIC_TYPE 15
|
|
Column("TYPE", Enum(&metric_type_values_typelib), NOT_NULL),
|
|
|
|
#define METRIC_DESC 16
|
|
Column("COMMENT", Varchar(NAME_LEN + 1), NOT_NULL),
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/**********************************************************************//**
|
|
Fill the information schema metrics table.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_metrics_fill(
|
|
/*=============*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE* table_to_fill) /*!< in/out: fill this table */
|
|
{
|
|
int count;
|
|
Field** fields;
|
|
double time_diff = 0;
|
|
monitor_info_t* monitor_info;
|
|
mon_type_t min_val;
|
|
mon_type_t max_val;
|
|
|
|
DBUG_ENTER("i_s_metrics_fill");
|
|
fields = table_to_fill->field;
|
|
|
|
for (count = 0; count < NUM_MONITOR; count++) {
|
|
monitor_info = srv_mon_get_info((monitor_id_t) count);
|
|
|
|
/* A good place to sanity check the Monitor ID */
|
|
ut_a(count == monitor_info->monitor_id);
|
|
|
|
/* If the item refers to a Module, nothing to fill,
|
|
continue. */
|
|
if ((monitor_info->monitor_type & MONITOR_MODULE)
|
|
|| (monitor_info->monitor_type & MONITOR_HIDDEN)) {
|
|
continue;
|
|
}
|
|
|
|
/* If this is an existing "status variable", and
|
|
its corresponding counter is still on, we need
|
|
to calculate the result from its corresponding
|
|
counter. */
|
|
if (monitor_info->monitor_type & MONITOR_EXISTING
|
|
&& MONITOR_IS_ON(count)) {
|
|
srv_mon_process_existing_counter((monitor_id_t) count,
|
|
MONITOR_GET_VALUE);
|
|
}
|
|
|
|
/* Fill in counter's basic information */
|
|
OK(field_store_string(fields[METRIC_NAME],
|
|
monitor_info->monitor_name));
|
|
|
|
OK(field_store_string(fields[METRIC_SUBSYS],
|
|
monitor_info->monitor_module));
|
|
|
|
OK(field_store_string(fields[METRIC_DESC],
|
|
monitor_info->monitor_desc));
|
|
|
|
/* Fill in counter values */
|
|
OK(fields[METRIC_VALUE_RESET]->store(
|
|
MONITOR_VALUE(count), FALSE));
|
|
|
|
OK(fields[METRIC_VALUE_START]->store(
|
|
MONITOR_VALUE_SINCE_START(count), FALSE));
|
|
|
|
/* If the max value is MAX_RESERVED, counter max
|
|
value has not been updated. Set the column value
|
|
to NULL. */
|
|
if (MONITOR_MAX_VALUE(count) == MAX_RESERVED
|
|
|| MONITOR_MAX_MIN_NOT_INIT(count)) {
|
|
fields[METRIC_MAX_VALUE_RESET]->set_null();
|
|
} else {
|
|
OK(fields[METRIC_MAX_VALUE_RESET]->store(
|
|
MONITOR_MAX_VALUE(count), FALSE));
|
|
fields[METRIC_MAX_VALUE_RESET]->set_notnull();
|
|
}
|
|
|
|
/* If the min value is MAX_RESERVED, counter min
|
|
value has not been updated. Set the column value
|
|
to NULL. */
|
|
if (MONITOR_MIN_VALUE(count) == MIN_RESERVED
|
|
|| MONITOR_MAX_MIN_NOT_INIT(count)) {
|
|
fields[METRIC_MIN_VALUE_RESET]->set_null();
|
|
} else {
|
|
OK(fields[METRIC_MIN_VALUE_RESET]->store(
|
|
MONITOR_MIN_VALUE(count), FALSE));
|
|
fields[METRIC_MIN_VALUE_RESET]->set_notnull();
|
|
}
|
|
|
|
/* Calculate the max value since counter started */
|
|
max_val = srv_mon_calc_max_since_start((monitor_id_t) count);
|
|
|
|
if (max_val == MAX_RESERVED
|
|
|| MONITOR_MAX_MIN_NOT_INIT(count)) {
|
|
fields[METRIC_MAX_VALUE_START]->set_null();
|
|
} else {
|
|
OK(fields[METRIC_MAX_VALUE_START]->store(
|
|
max_val, FALSE));
|
|
fields[METRIC_MAX_VALUE_START]->set_notnull();
|
|
}
|
|
|
|
/* Calculate the min value since counter started */
|
|
min_val = srv_mon_calc_min_since_start((monitor_id_t) count);
|
|
|
|
if (min_val == MIN_RESERVED
|
|
|| MONITOR_MAX_MIN_NOT_INIT(count)) {
|
|
fields[METRIC_MIN_VALUE_START]->set_null();
|
|
} else {
|
|
OK(fields[METRIC_MIN_VALUE_START]->store(
|
|
min_val, FALSE));
|
|
|
|
fields[METRIC_MIN_VALUE_START]->set_notnull();
|
|
}
|
|
|
|
/* If monitor has been enabled (no matter it is disabled
|
|
or not now), fill METRIC_START_TIME and METRIC_TIME_ELAPSED
|
|
field */
|
|
if (MONITOR_FIELD(count, mon_start_time)) {
|
|
OK(field_store_time_t(fields[METRIC_START_TIME],
|
|
(time_t)MONITOR_FIELD(count, mon_start_time)));
|
|
fields[METRIC_START_TIME]->set_notnull();
|
|
|
|
/* If monitor is enabled, the TIME_ELAPSED is the
|
|
time difference between current and time when monitor
|
|
is enabled. Otherwise, it is the time difference
|
|
between time when monitor is enabled and time
|
|
when it is disabled */
|
|
if (MONITOR_IS_ON(count)) {
|
|
time_diff = difftime(time(NULL),
|
|
MONITOR_FIELD(count, mon_start_time));
|
|
} else {
|
|
time_diff = difftime(
|
|
MONITOR_FIELD(count, mon_stop_time),
|
|
MONITOR_FIELD(count, mon_start_time));
|
|
}
|
|
|
|
OK(fields[METRIC_TIME_ELAPSED]->store(
|
|
time_diff));
|
|
fields[METRIC_TIME_ELAPSED]->set_notnull();
|
|
} else {
|
|
fields[METRIC_START_TIME]->set_null();
|
|
fields[METRIC_TIME_ELAPSED]->set_null();
|
|
time_diff = 0;
|
|
}
|
|
|
|
/* Unless MONITOR_NO_AVERAGE is set, we must
|
|
to calculate the average value. If this is a monitor set
|
|
owner marked by MONITOR_SET_OWNER, divide
|
|
the value by another counter (number of calls) designated
|
|
by monitor_info->monitor_related_id.
|
|
Otherwise average the counter value by the time between the
|
|
time that the counter is enabled and time it is disabled
|
|
or time it is sampled. */
|
|
if ((monitor_info->monitor_type
|
|
& (MONITOR_NO_AVERAGE | MONITOR_SET_OWNER))
|
|
== MONITOR_SET_OWNER
|
|
&& monitor_info->monitor_related_id) {
|
|
mon_type_t value_start
|
|
= MONITOR_VALUE_SINCE_START(
|
|
monitor_info->monitor_related_id);
|
|
|
|
if (value_start) {
|
|
OK(fields[METRIC_AVG_VALUE_START]->store(
|
|
MONITOR_VALUE_SINCE_START(count)
|
|
/ value_start, FALSE));
|
|
|
|
fields[METRIC_AVG_VALUE_START]->set_notnull();
|
|
} else {
|
|
fields[METRIC_AVG_VALUE_START]->set_null();
|
|
}
|
|
|
|
if (mon_type_t related_value =
|
|
MONITOR_VALUE(monitor_info->monitor_related_id)) {
|
|
OK(fields[METRIC_AVG_VALUE_RESET]
|
|
->store(MONITOR_VALUE(count)
|
|
/ related_value, false));
|
|
fields[METRIC_AVG_VALUE_RESET]->set_notnull();
|
|
} else {
|
|
fields[METRIC_AVG_VALUE_RESET]->set_null();
|
|
}
|
|
} else if (!(monitor_info->monitor_type
|
|
& (MONITOR_NO_AVERAGE
|
|
| MONITOR_DISPLAY_CURRENT))) {
|
|
if (time_diff != 0) {
|
|
OK(fields[METRIC_AVG_VALUE_START]->store(
|
|
(double) MONITOR_VALUE_SINCE_START(
|
|
count) / time_diff));
|
|
fields[METRIC_AVG_VALUE_START]->set_notnull();
|
|
} else {
|
|
fields[METRIC_AVG_VALUE_START]->set_null();
|
|
}
|
|
|
|
if (MONITOR_FIELD(count, mon_reset_time)) {
|
|
/* calculate the time difference since last
|
|
reset */
|
|
if (MONITOR_IS_ON(count)) {
|
|
time_diff = difftime(
|
|
time(NULL), MONITOR_FIELD(
|
|
count, mon_reset_time));
|
|
} else {
|
|
time_diff = difftime(
|
|
MONITOR_FIELD(count, mon_stop_time),
|
|
MONITOR_FIELD(count, mon_reset_time));
|
|
}
|
|
} else {
|
|
time_diff = 0;
|
|
}
|
|
|
|
if (time_diff != 0) {
|
|
OK(fields[METRIC_AVG_VALUE_RESET]->store(
|
|
static_cast<double>(
|
|
MONITOR_VALUE(count))
|
|
/ time_diff));
|
|
fields[METRIC_AVG_VALUE_RESET]->set_notnull();
|
|
} else {
|
|
fields[METRIC_AVG_VALUE_RESET]->set_null();
|
|
}
|
|
} else {
|
|
fields[METRIC_AVG_VALUE_START]->set_null();
|
|
fields[METRIC_AVG_VALUE_RESET]->set_null();
|
|
}
|
|
|
|
if (MONITOR_IS_ON(count)) {
|
|
/* If monitor is on, the stop time will set to NULL */
|
|
fields[METRIC_STOP_TIME]->set_null();
|
|
|
|
/* Display latest Monitor Reset Time only if Monitor
|
|
counter is on. */
|
|
if (MONITOR_FIELD(count, mon_reset_time)) {
|
|
OK(field_store_time_t(
|
|
fields[METRIC_RESET_TIME],
|
|
(time_t)MONITOR_FIELD(
|
|
count, mon_reset_time)));
|
|
fields[METRIC_RESET_TIME]->set_notnull();
|
|
} else {
|
|
fields[METRIC_RESET_TIME]->set_null();
|
|
}
|
|
|
|
OK(fields[METRIC_STATUS]->store(1, true));
|
|
} else {
|
|
if (MONITOR_FIELD(count, mon_stop_time)) {
|
|
OK(field_store_time_t(fields[METRIC_STOP_TIME],
|
|
(time_t)MONITOR_FIELD(count, mon_stop_time)));
|
|
fields[METRIC_STOP_TIME]->set_notnull();
|
|
} else {
|
|
fields[METRIC_STOP_TIME]->set_null();
|
|
}
|
|
|
|
fields[METRIC_RESET_TIME]->set_null();
|
|
|
|
OK(fields[METRIC_STATUS]->store(0, true));
|
|
}
|
|
|
|
uint metric_type;
|
|
|
|
if (monitor_info->monitor_type & MONITOR_DISPLAY_CURRENT) {
|
|
metric_type = 1; /* "value" */
|
|
} else if (monitor_info->monitor_type & MONITOR_EXISTING) {
|
|
metric_type = 2; /* "status_counter" */
|
|
} else if (monitor_info->monitor_type & MONITOR_SET_OWNER) {
|
|
metric_type = 3; /* "set_owner" */
|
|
} else if (monitor_info->monitor_type & MONITOR_SET_MEMBER) {
|
|
metric_type = 4; /* "set_member" */
|
|
} else {
|
|
metric_type = 5; /* "counter" */
|
|
}
|
|
|
|
OK(fields[METRIC_TYPE]->store(metric_type, true));
|
|
|
|
OK(schema_table_store_record(thd, table_to_fill));
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Function to fill information schema metrics tables.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_metrics_fill_table(
|
|
/*===================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (not used) */
|
|
{
|
|
DBUG_ENTER("i_s_metrics_fill_table");
|
|
|
|
/* deny access to non-superusers */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
i_s_metrics_fill(thd, tables->table);
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.innodb_metrics
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
innodb_metrics_init(
|
|
/*================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("innodb_metrics_init");
|
|
|
|
schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::innodb_metrics_fields_info;
|
|
schema->fill_table = i_s_metrics_fill_table;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_metrics =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_METRICS",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB Metrics Info",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
innodb_metrics_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
namespace Show {
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_ft_default_stopword */
|
|
static ST_FIELD_INFO i_s_stopword_fields_info[]=
|
|
{
|
|
#define STOPWORD_VALUE 0
|
|
Column("value", Varchar(TRX_ID_MAX_LEN + 1), NOT_NULL),
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/*******************************************************************//**
|
|
Fill the dynamic table information_schema.innodb_ft_default_stopword.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_stopword_fill(
|
|
/*==============*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (not used) */
|
|
{
|
|
Field** fields;
|
|
ulint i = 0;
|
|
TABLE* table = (TABLE*) tables->table;
|
|
|
|
DBUG_ENTER("i_s_stopword_fill");
|
|
|
|
fields = table->field;
|
|
|
|
/* Fill with server default stopword list in array
|
|
fts_default_stopword */
|
|
while (fts_default_stopword[i]) {
|
|
OK(field_store_string(fields[STOPWORD_VALUE],
|
|
fts_default_stopword[i]));
|
|
|
|
OK(schema_table_store_record(thd, table));
|
|
i++;
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table information_schema.innodb_ft_default_stopword.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_stopword_init(
|
|
/*==============*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
DBUG_ENTER("i_s_stopword_init");
|
|
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::i_s_stopword_fields_info;
|
|
schema->fill_table = i_s_stopword_fill;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_ft_default_stopword =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_FT_DEFAULT_STOPWORD",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"Default stopword list for InnoDB Full Text Search",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_stopword_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
namespace Show {
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED
|
|
INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED */
|
|
static ST_FIELD_INFO i_s_fts_doc_fields_info[]=
|
|
{
|
|
#define I_S_FTS_DOC_ID 0
|
|
Column("DOC_ID", ULonglong(), NOT_NULL),
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/*******************************************************************//**
|
|
Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED or
|
|
INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_fts_deleted_generic_fill(
|
|
/*=========================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
ibool being_deleted) /*!< in: BEING_DELTED table */
|
|
{
|
|
Field** fields;
|
|
TABLE* table = (TABLE*) tables->table;
|
|
trx_t* trx;
|
|
fts_table_t fts_table;
|
|
fts_doc_ids_t* deleted;
|
|
dict_table_t* user_table;
|
|
|
|
DBUG_ENTER("i_s_fts_deleted_generic_fill");
|
|
|
|
/* deny access to non-superusers */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
MDL_ticket* mdl_ticket = nullptr;
|
|
user_table = dict_table_open_on_id(
|
|
innodb_ft_aux_table_id, false, DICT_TABLE_OP_NORMAL,
|
|
thd, &mdl_ticket);
|
|
|
|
if (!user_table) {
|
|
DBUG_RETURN(0);
|
|
} else if (!dict_table_has_fts_index(user_table)
|
|
|| !user_table->is_readable()) {
|
|
dict_table_close(user_table, false, thd, mdl_ticket);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
deleted = fts_doc_ids_create();
|
|
|
|
trx = trx_create();
|
|
trx->op_info = "Select for FTS DELETE TABLE";
|
|
|
|
FTS_INIT_FTS_TABLE(&fts_table,
|
|
(being_deleted) ? "BEING_DELETED" : "DELETED",
|
|
FTS_COMMON_TABLE, user_table);
|
|
|
|
fts_table_fetch_doc_ids(trx, &fts_table, deleted);
|
|
|
|
dict_table_close(user_table, false, thd, mdl_ticket);
|
|
|
|
trx->free();
|
|
|
|
fields = table->field;
|
|
|
|
int ret = 0;
|
|
|
|
for (ulint j = 0; j < ib_vector_size(deleted->doc_ids); ++j) {
|
|
doc_id_t doc_id;
|
|
|
|
doc_id = *(doc_id_t*) ib_vector_get_const(deleted->doc_ids, j);
|
|
|
|
BREAK_IF(ret = fields[I_S_FTS_DOC_ID]->store(doc_id, true));
|
|
|
|
BREAK_IF(ret = schema_table_store_record(thd, table));
|
|
}
|
|
|
|
fts_doc_ids_free(deleted);
|
|
|
|
DBUG_RETURN(ret);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_fts_deleted_fill(
|
|
/*=================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (ignored) */
|
|
{
|
|
DBUG_ENTER("i_s_fts_deleted_fill");
|
|
|
|
DBUG_RETURN(i_s_fts_deleted_generic_fill(thd, tables, FALSE));
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_fts_deleted_init(
|
|
/*=================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
DBUG_ENTER("i_s_fts_deleted_init");
|
|
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::i_s_fts_doc_fields_info;
|
|
schema->fill_table = i_s_fts_deleted_fill;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_ft_deleted =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_FT_DELETED",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"INNODB AUXILIARY FTS DELETED TABLE",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_fts_deleted_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
/*******************************************************************//**
|
|
Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_fts_being_deleted_fill(
|
|
/*=======================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (ignored) */
|
|
{
|
|
DBUG_ENTER("i_s_fts_being_deleted_fill");
|
|
|
|
DBUG_RETURN(i_s_fts_deleted_generic_fill(thd, tables, TRUE));
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_fts_being_deleted_init(
|
|
/*=======================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
DBUG_ENTER("i_s_fts_deleted_init");
|
|
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::i_s_fts_doc_fields_info;
|
|
schema->fill_table = i_s_fts_being_deleted_fill;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_ft_being_deleted =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_FT_BEING_DELETED",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"INNODB AUXILIARY FTS BEING DELETED TABLE",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_fts_being_deleted_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
|
|
namespace Show {
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED and
|
|
INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE */
|
|
static ST_FIELD_INFO i_s_fts_index_fields_info[]=
|
|
{
|
|
#define I_S_FTS_WORD 0
|
|
Column("WORD", Varchar(FTS_MAX_WORD_LEN + 1), NOT_NULL),
|
|
|
|
#define I_S_FTS_FIRST_DOC_ID 1
|
|
Column("FIRST_DOC_ID", ULonglong(), NOT_NULL),
|
|
|
|
#define I_S_FTS_LAST_DOC_ID 2
|
|
Column("LAST_DOC_ID", ULonglong(), NOT_NULL),
|
|
|
|
#define I_S_FTS_DOC_COUNT 3
|
|
Column("DOC_COUNT", ULonglong(), NOT_NULL),
|
|
|
|
#define I_S_FTS_ILIST_DOC_ID 4
|
|
Column("DOC_ID", ULonglong(), NOT_NULL),
|
|
|
|
#define I_S_FTS_ILIST_DOC_POS 5
|
|
Column("POSITION", ULonglong(), NOT_NULL),
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/*******************************************************************//**
|
|
Go through the Doc Node and its ilist, fill the dynamic table
|
|
INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED for one FTS index on the table.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_fts_index_cache_fill_one_index(
|
|
/*===============================*/
|
|
fts_index_cache_t* index_cache, /*!< in: FTS index cache */
|
|
THD* thd, /*!< in: thread */
|
|
fts_string_t* conv_str, /*!< in/out: buffer */
|
|
TABLE_LIST* tables) /*!< in/out: tables to fill */
|
|
{
|
|
TABLE* table = (TABLE*) tables->table;
|
|
Field** fields;
|
|
CHARSET_INFO* index_charset;
|
|
const ib_rbt_node_t* rbt_node;
|
|
uint dummy_errors;
|
|
char* word_str;
|
|
|
|
DBUG_ENTER("i_s_fts_index_cache_fill_one_index");
|
|
|
|
fields = table->field;
|
|
|
|
index_charset = index_cache->charset;
|
|
conv_str->f_n_char = 0;
|
|
|
|
int ret = 0;
|
|
|
|
/* Go through each word in the index cache */
|
|
for (rbt_node = rbt_first(index_cache->words);
|
|
rbt_node;
|
|
rbt_node = rbt_next(index_cache->words, rbt_node)) {
|
|
fts_tokenizer_word_t* word;
|
|
|
|
word = rbt_value(fts_tokenizer_word_t, rbt_node);
|
|
|
|
/* Convert word from index charset to system_charset_info */
|
|
if (index_charset->cset != system_charset_info->cset) {
|
|
conv_str->f_n_char = my_convert(
|
|
reinterpret_cast<char*>(conv_str->f_str),
|
|
static_cast<uint32>(conv_str->f_len),
|
|
system_charset_info,
|
|
reinterpret_cast<char*>(word->text.f_str),
|
|
static_cast<uint32>(word->text.f_len),
|
|
index_charset, &dummy_errors);
|
|
ut_ad(conv_str->f_n_char <= conv_str->f_len);
|
|
conv_str->f_str[conv_str->f_n_char] = 0;
|
|
word_str = reinterpret_cast<char*>(conv_str->f_str);
|
|
} else {
|
|
word_str = reinterpret_cast<char*>(word->text.f_str);
|
|
}
|
|
|
|
/* Decrypt the ilist, and display Dod ID and word position */
|
|
for (ulint i = 0; i < ib_vector_size(word->nodes); i++) {
|
|
fts_node_t* node;
|
|
const byte* ptr;
|
|
ulint decoded = 0;
|
|
doc_id_t doc_id = 0;
|
|
|
|
node = static_cast<fts_node_t*> (ib_vector_get(
|
|
word->nodes, i));
|
|
|
|
ptr = node->ilist;
|
|
|
|
while (decoded < node->ilist_size) {
|
|
|
|
doc_id += fts_decode_vlc(&ptr);
|
|
|
|
/* Get position info */
|
|
while (*ptr) {
|
|
|
|
OK(field_store_string(
|
|
fields[I_S_FTS_WORD],
|
|
word_str));
|
|
|
|
OK(fields[I_S_FTS_FIRST_DOC_ID]->store(
|
|
node->first_doc_id,
|
|
true));
|
|
|
|
OK(fields[I_S_FTS_LAST_DOC_ID]->store(
|
|
node->last_doc_id,
|
|
true));
|
|
|
|
OK(fields[I_S_FTS_DOC_COUNT]->store(
|
|
node->doc_count, true));
|
|
|
|
OK(fields[I_S_FTS_ILIST_DOC_ID]->store(
|
|
doc_id, true));
|
|
|
|
OK(fields[I_S_FTS_ILIST_DOC_POS]->store(
|
|
fts_decode_vlc(&ptr), true));
|
|
|
|
OK(schema_table_store_record(
|
|
thd, table));
|
|
}
|
|
|
|
++ptr;
|
|
|
|
decoded = ptr - (byte*) node->ilist;
|
|
}
|
|
}
|
|
}
|
|
|
|
DBUG_RETURN(ret);
|
|
}
|
|
/*******************************************************************//**
|
|
Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_fts_index_cache_fill(
|
|
/*=====================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (ignored) */
|
|
{
|
|
dict_table_t* user_table;
|
|
fts_cache_t* cache;
|
|
|
|
DBUG_ENTER("i_s_fts_index_cache_fill");
|
|
|
|
/* deny access to non-superusers */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
MDL_ticket* mdl_ticket = nullptr;
|
|
user_table = dict_table_open_on_id(
|
|
innodb_ft_aux_table_id, false, DICT_TABLE_OP_NORMAL,
|
|
thd, &mdl_ticket);
|
|
|
|
if (!user_table) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
if (!user_table->fts || !user_table->fts->cache) {
|
|
dict_table_close(user_table, false, thd, mdl_ticket);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
cache = user_table->fts->cache;
|
|
|
|
int ret = 0;
|
|
fts_string_t conv_str;
|
|
byte word[HA_FT_MAXBYTELEN + 1];
|
|
conv_str.f_len = sizeof word;
|
|
conv_str.f_str = word;
|
|
|
|
mysql_mutex_lock(&cache->lock);
|
|
|
|
for (ulint i = 0; i < ib_vector_size(cache->indexes); i++) {
|
|
fts_index_cache_t* index_cache;
|
|
|
|
index_cache = static_cast<fts_index_cache_t*> (
|
|
ib_vector_get(cache->indexes, i));
|
|
|
|
BREAK_IF(ret = i_s_fts_index_cache_fill_one_index(
|
|
index_cache, thd, &conv_str, tables));
|
|
}
|
|
|
|
mysql_mutex_unlock(&cache->lock);
|
|
dict_table_close(user_table, false, thd, mdl_ticket);
|
|
|
|
DBUG_RETURN(ret);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_fts_index_cache_init(
|
|
/*=====================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
DBUG_ENTER("i_s_fts_index_cache_init");
|
|
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::i_s_fts_index_fields_info;
|
|
schema->fill_table = i_s_fts_index_cache_fill;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_ft_index_cache =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_FT_INDEX_CACHE",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"INNODB AUXILIARY FTS INDEX CACHED",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_fts_index_cache_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
/*******************************************************************//**
|
|
Go through a FTS index auxiliary table, fetch its rows and fill
|
|
FTS word cache structure.
|
|
@return DB_SUCCESS on success, otherwise error code */
|
|
static
|
|
dberr_t
|
|
i_s_fts_index_table_fill_selected(
|
|
/*==============================*/
|
|
dict_index_t* index, /*!< in: FTS index */
|
|
ib_vector_t* words, /*!< in/out: vector to hold
|
|
fetched words */
|
|
ulint selected, /*!< in: selected FTS index */
|
|
fts_string_t* word) /*!< in: word to select */
|
|
{
|
|
pars_info_t* info;
|
|
fts_table_t fts_table;
|
|
trx_t* trx;
|
|
que_t* graph;
|
|
dberr_t error;
|
|
fts_fetch_t fetch;
|
|
char table_name[MAX_FULL_NAME_LEN];
|
|
|
|
info = pars_info_create();
|
|
|
|
fetch.read_arg = words;
|
|
fetch.read_record = fts_optimize_index_fetch_node;
|
|
fetch.total_memory = 0;
|
|
|
|
DBUG_EXECUTE_IF("fts_instrument_result_cache_limit",
|
|
fts_result_cache_limit = 8192;
|
|
);
|
|
|
|
trx = trx_create();
|
|
|
|
trx->op_info = "fetching FTS index nodes";
|
|
|
|
pars_info_bind_function(info, "my_func", fetch.read_record, &fetch);
|
|
pars_info_bind_varchar_literal(info, "word", word->f_str, word->f_len);
|
|
|
|
FTS_INIT_INDEX_TABLE(&fts_table, fts_get_suffix(selected),
|
|
FTS_INDEX_TABLE, index);
|
|
fts_get_table_name(&fts_table, table_name);
|
|
pars_info_bind_id(info, "table_name", table_name);
|
|
|
|
graph = fts_parse_sql(
|
|
&fts_table, info,
|
|
"DECLARE FUNCTION my_func;\n"
|
|
"DECLARE CURSOR c IS"
|
|
" SELECT word, doc_count, first_doc_id, last_doc_id,"
|
|
" ilist\n"
|
|
" FROM $table_name WHERE word >= :word;\n"
|
|
"BEGIN\n"
|
|
"\n"
|
|
"OPEN c;\n"
|
|
"WHILE 1 = 1 LOOP\n"
|
|
" FETCH c INTO my_func();\n"
|
|
" IF c % NOTFOUND THEN\n"
|
|
" EXIT;\n"
|
|
" END IF;\n"
|
|
"END LOOP;\n"
|
|
"CLOSE c;");
|
|
|
|
for (;;) {
|
|
error = fts_eval_sql(trx, graph);
|
|
|
|
if (UNIV_LIKELY(error == DB_SUCCESS)) {
|
|
fts_sql_commit(trx);
|
|
|
|
break;
|
|
} else {
|
|
fts_sql_rollback(trx);
|
|
|
|
if (error == DB_LOCK_WAIT_TIMEOUT) {
|
|
ib::warn() << "Lock wait timeout reading"
|
|
" FTS index. Retrying!";
|
|
|
|
trx->error_state = DB_SUCCESS;
|
|
} else {
|
|
ib::error() << "Error occurred while reading"
|
|
" FTS index: " << error;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
que_graph_free(graph);
|
|
|
|
trx->free();
|
|
|
|
if (fetch.total_memory >= fts_result_cache_limit) {
|
|
error = DB_FTS_EXCEED_RESULT_CACHE_LIMIT;
|
|
}
|
|
|
|
return(error);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Free words. */
|
|
static
|
|
void
|
|
i_s_fts_index_table_free_one_fetch(
|
|
/*===============================*/
|
|
ib_vector_t* words) /*!< in: words fetched */
|
|
{
|
|
for (ulint i = 0; i < ib_vector_size(words); i++) {
|
|
fts_word_t* word;
|
|
|
|
word = static_cast<fts_word_t*>(ib_vector_get(words, i));
|
|
|
|
for (ulint j = 0; j < ib_vector_size(word->nodes); j++) {
|
|
fts_node_t* node;
|
|
|
|
node = static_cast<fts_node_t*> (ib_vector_get(
|
|
word->nodes, j));
|
|
ut_free(node->ilist);
|
|
}
|
|
|
|
fts_word_free(word);
|
|
}
|
|
|
|
ib_vector_reset(words);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Go through words, fill INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_fts_index_table_fill_one_fetch(
|
|
/*===============================*/
|
|
CHARSET_INFO* index_charset, /*!< in: FTS index charset */
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
ib_vector_t* words, /*!< in: words fetched */
|
|
fts_string_t* conv_str, /*!< in: string for conversion*/
|
|
bool has_more) /*!< in: has more to fetch */
|
|
{
|
|
TABLE* table = (TABLE*) tables->table;
|
|
Field** fields;
|
|
uint dummy_errors;
|
|
char* word_str;
|
|
ulint words_size;
|
|
int ret = 0;
|
|
|
|
DBUG_ENTER("i_s_fts_index_table_fill_one_fetch");
|
|
|
|
fields = table->field;
|
|
|
|
words_size = ib_vector_size(words);
|
|
if (has_more) {
|
|
/* the last word is not fetched completely. */
|
|
ut_ad(words_size > 1);
|
|
words_size -= 1;
|
|
}
|
|
|
|
/* Go through each word in the index cache */
|
|
for (ulint i = 0; i < words_size; i++) {
|
|
fts_word_t* word;
|
|
|
|
word = static_cast<fts_word_t*>(ib_vector_get(words, i));
|
|
|
|
word->text.f_str[word->text.f_len] = 0;
|
|
|
|
/* Convert word from index charset to system_charset_info */
|
|
if (index_charset->cset != system_charset_info->cset) {
|
|
conv_str->f_n_char = my_convert(
|
|
reinterpret_cast<char*>(conv_str->f_str),
|
|
static_cast<uint32>(conv_str->f_len),
|
|
system_charset_info,
|
|
reinterpret_cast<char*>(word->text.f_str),
|
|
static_cast<uint32>(word->text.f_len),
|
|
index_charset, &dummy_errors);
|
|
ut_ad(conv_str->f_n_char <= conv_str->f_len);
|
|
conv_str->f_str[conv_str->f_n_char] = 0;
|
|
word_str = reinterpret_cast<char*>(conv_str->f_str);
|
|
} else {
|
|
word_str = reinterpret_cast<char*>(word->text.f_str);
|
|
}
|
|
|
|
/* Decrypt the ilist, and display Dod ID and word position */
|
|
for (ulint i = 0; i < ib_vector_size(word->nodes); i++) {
|
|
fts_node_t* node;
|
|
const byte* ptr;
|
|
ulint decoded = 0;
|
|
doc_id_t doc_id = 0;
|
|
|
|
node = static_cast<fts_node_t*> (ib_vector_get(
|
|
word->nodes, i));
|
|
|
|
ptr = node->ilist;
|
|
|
|
while (decoded < node->ilist_size) {
|
|
doc_id += fts_decode_vlc(&ptr);
|
|
|
|
/* Get position info */
|
|
while (*ptr) {
|
|
|
|
OK(field_store_string(
|
|
fields[I_S_FTS_WORD],
|
|
word_str));
|
|
|
|
OK(fields[I_S_FTS_FIRST_DOC_ID]->store(
|
|
longlong(node->first_doc_id), true));
|
|
|
|
OK(fields[I_S_FTS_LAST_DOC_ID]->store(
|
|
longlong(node->last_doc_id), true));
|
|
|
|
OK(fields[I_S_FTS_DOC_COUNT]->store(
|
|
node->doc_count, true));
|
|
|
|
OK(fields[I_S_FTS_ILIST_DOC_ID]->store(
|
|
longlong(doc_id), true));
|
|
|
|
OK(fields[I_S_FTS_ILIST_DOC_POS]->store(
|
|
fts_decode_vlc(&ptr), true));
|
|
|
|
OK(schema_table_store_record(
|
|
thd, table));
|
|
}
|
|
|
|
++ptr;
|
|
|
|
decoded = ptr - (byte*) node->ilist;
|
|
}
|
|
}
|
|
}
|
|
|
|
DBUG_RETURN(ret);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Go through a FTS index and its auxiliary tables, fetch rows in each table
|
|
and fill INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_fts_index_table_fill_one_index(
|
|
/*===============================*/
|
|
dict_index_t* index, /*!< in: FTS index */
|
|
THD* thd, /*!< in: thread */
|
|
fts_string_t* conv_str, /*!< in/out: buffer */
|
|
TABLE_LIST* tables) /*!< in/out: tables to fill */
|
|
{
|
|
ib_vector_t* words;
|
|
mem_heap_t* heap;
|
|
CHARSET_INFO* index_charset;
|
|
dberr_t error;
|
|
int ret = 0;
|
|
|
|
DBUG_ENTER("i_s_fts_index_table_fill_one_index");
|
|
DBUG_ASSERT(!dict_index_is_online_ddl(index));
|
|
|
|
heap = mem_heap_create(1024);
|
|
|
|
words = ib_vector_create(ib_heap_allocator_create(heap),
|
|
sizeof(fts_word_t), 256);
|
|
|
|
index_charset = fts_index_get_charset(index);
|
|
|
|
/* Iterate through each auxiliary table as described in
|
|
fts_index_selector */
|
|
for (ulint selected = 0; selected < FTS_NUM_AUX_INDEX; selected++) {
|
|
fts_string_t word;
|
|
bool has_more = false;
|
|
|
|
word.f_str = NULL;
|
|
word.f_len = 0;
|
|
word.f_n_char = 0;
|
|
|
|
do {
|
|
/* Fetch from index */
|
|
error = i_s_fts_index_table_fill_selected(
|
|
index, words, selected, &word);
|
|
|
|
if (error == DB_SUCCESS) {
|
|
has_more = false;
|
|
} else if (error == DB_FTS_EXCEED_RESULT_CACHE_LIMIT) {
|
|
has_more = true;
|
|
} else {
|
|
i_s_fts_index_table_free_one_fetch(words);
|
|
ret = 1;
|
|
goto func_exit;
|
|
}
|
|
|
|
if (has_more) {
|
|
fts_word_t* last_word;
|
|
|
|
/* Prepare start point for next fetch */
|
|
last_word = static_cast<fts_word_t*>(ib_vector_last(words));
|
|
ut_ad(last_word != NULL);
|
|
fts_string_dup(&word, &last_word->text, heap);
|
|
}
|
|
|
|
/* Fill into tables */
|
|
ret = i_s_fts_index_table_fill_one_fetch(
|
|
index_charset, thd, tables, words, conv_str,
|
|
has_more);
|
|
i_s_fts_index_table_free_one_fetch(words);
|
|
|
|
if (ret != 0) {
|
|
goto func_exit;
|
|
}
|
|
} while (has_more);
|
|
}
|
|
|
|
func_exit:
|
|
mem_heap_free(heap);
|
|
|
|
DBUG_RETURN(ret);
|
|
}
|
|
/*******************************************************************//**
|
|
Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_fts_index_table_fill(
|
|
/*=====================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (ignored) */
|
|
{
|
|
dict_table_t* user_table;
|
|
dict_index_t* index;
|
|
|
|
DBUG_ENTER("i_s_fts_index_table_fill");
|
|
|
|
/* deny access to non-superusers */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
MDL_ticket* mdl_ticket = nullptr;
|
|
user_table = dict_table_open_on_id(
|
|
innodb_ft_aux_table_id, false, DICT_TABLE_OP_NORMAL,
|
|
thd, &mdl_ticket);
|
|
|
|
if (!user_table) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int ret = 0;
|
|
fts_string_t conv_str;
|
|
conv_str.f_len = system_charset_info->mbmaxlen
|
|
* FTS_MAX_WORD_LEN_IN_CHAR;
|
|
conv_str.f_str = static_cast<byte*>(ut_malloc_nokey(conv_str.f_len));
|
|
|
|
for (index = dict_table_get_first_index(user_table);
|
|
index; index = dict_table_get_next_index(index)) {
|
|
if (index->type & DICT_FTS) {
|
|
BREAK_IF(ret = i_s_fts_index_table_fill_one_index(
|
|
index, thd, &conv_str, tables));
|
|
}
|
|
}
|
|
|
|
dict_table_close(user_table, false, thd, mdl_ticket);
|
|
|
|
ut_free(conv_str.f_str);
|
|
|
|
DBUG_RETURN(ret);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_fts_index_table_init(
|
|
/*=====================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
DBUG_ENTER("i_s_fts_index_table_init");
|
|
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::i_s_fts_index_fields_info;
|
|
schema->fill_table = i_s_fts_index_table_fill;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_ft_index_table =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_FT_INDEX_TABLE",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"INNODB AUXILIARY FTS INDEX TABLE",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_fts_index_table_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
|
|
namespace Show {
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_FT_CONFIG */
|
|
static ST_FIELD_INFO i_s_fts_config_fields_info[]=
|
|
{
|
|
#define FTS_CONFIG_KEY 0
|
|
Column("KEY", Varchar(NAME_LEN + 1), NOT_NULL),
|
|
|
|
#define FTS_CONFIG_VALUE 1
|
|
Column("VALUE", Varchar(NAME_LEN + 1), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
static const char* fts_config_key[] = {
|
|
FTS_OPTIMIZE_LIMIT_IN_SECS,
|
|
FTS_SYNCED_DOC_ID,
|
|
FTS_STOPWORD_TABLE_NAME,
|
|
FTS_USE_STOPWORD,
|
|
NULL
|
|
};
|
|
|
|
/*******************************************************************//**
|
|
Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_CONFIG
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_fts_config_fill(
|
|
/*================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (ignored) */
|
|
{
|
|
Field** fields;
|
|
TABLE* table = (TABLE*) tables->table;
|
|
trx_t* trx;
|
|
fts_table_t fts_table;
|
|
dict_table_t* user_table;
|
|
ulint i = 0;
|
|
dict_index_t* index = NULL;
|
|
unsigned char str[FTS_MAX_CONFIG_VALUE_LEN + 1];
|
|
|
|
DBUG_ENTER("i_s_fts_config_fill");
|
|
|
|
/* deny access to non-superusers */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
MDL_ticket* mdl_ticket = nullptr;
|
|
user_table = dict_table_open_on_id(
|
|
innodb_ft_aux_table_id, false, DICT_TABLE_OP_NORMAL,
|
|
thd, &mdl_ticket);
|
|
|
|
if (!user_table) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
if (!dict_table_has_fts_index(user_table)) {
|
|
dict_table_close(user_table, false, thd, mdl_ticket);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
fields = table->field;
|
|
|
|
trx = trx_create();
|
|
trx->op_info = "Select for FTS CONFIG TABLE";
|
|
|
|
FTS_INIT_FTS_TABLE(&fts_table, "CONFIG", FTS_COMMON_TABLE, user_table);
|
|
|
|
if (!ib_vector_is_empty(user_table->fts->indexes)) {
|
|
index = (dict_index_t*) ib_vector_getp_const(
|
|
user_table->fts->indexes, 0);
|
|
DBUG_ASSERT(!dict_index_is_online_ddl(index));
|
|
}
|
|
|
|
int ret = 0;
|
|
|
|
while (fts_config_key[i]) {
|
|
fts_string_t value;
|
|
char* key_name;
|
|
ulint allocated = FALSE;
|
|
|
|
value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
|
|
|
|
value.f_str = str;
|
|
|
|
if (index
|
|
&& strcmp(fts_config_key[i], FTS_TOTAL_WORD_COUNT) == 0) {
|
|
key_name = fts_config_create_index_param_name(
|
|
fts_config_key[i], index);
|
|
allocated = TRUE;
|
|
} else {
|
|
key_name = (char*) fts_config_key[i];
|
|
}
|
|
|
|
fts_config_get_value(trx, &fts_table, key_name, &value);
|
|
|
|
if (allocated) {
|
|
ut_free(key_name);
|
|
}
|
|
|
|
BREAK_IF(ret = field_store_string(
|
|
fields[FTS_CONFIG_KEY], fts_config_key[i]));
|
|
|
|
BREAK_IF(ret = field_store_string(
|
|
fields[FTS_CONFIG_VALUE],
|
|
reinterpret_cast<const char*>(value.f_str)));
|
|
|
|
BREAK_IF(ret = schema_table_store_record(thd, table));
|
|
|
|
i++;
|
|
}
|
|
|
|
fts_sql_commit(trx);
|
|
|
|
dict_table_close(user_table, false, thd, mdl_ticket);
|
|
|
|
trx->free();
|
|
|
|
DBUG_RETURN(ret);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_CONFIG
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_fts_config_init(
|
|
/*=================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
DBUG_ENTER("i_s_fts_config_init");
|
|
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::i_s_fts_config_fields_info;
|
|
schema->fill_table = i_s_fts_config_fill;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_ft_config =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_FT_CONFIG",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"INNODB AUXILIARY FTS CONFIG TABLE",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_fts_config_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
namespace Show {
|
|
/* Fields of the dynamic table INNODB_BUFFER_POOL_STATS. */
|
|
static ST_FIELD_INFO i_s_innodb_buffer_stats_fields_info[]=
|
|
{
|
|
#define IDX_BUF_STATS_POOL_ID 0
|
|
Column("POOL_ID", ULong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_POOL_SIZE 1
|
|
Column("POOL_SIZE", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_FREE_BUFFERS 2
|
|
Column("FREE_BUFFERS", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_LRU_LEN 3
|
|
Column("DATABASE_PAGES", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_OLD_LRU_LEN 4
|
|
Column("OLD_DATABASE_PAGES", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_FLUSH_LIST_LEN 5
|
|
Column("MODIFIED_DATABASE_PAGES", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_PENDING_ZIP 6
|
|
Column("PENDING_DECOMPRESS", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_PENDING_READ 7
|
|
Column("PENDING_READS",ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_FLUSH_LRU 8
|
|
Column("PENDING_FLUSH_LRU",ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_FLUSH_LIST 9
|
|
Column("PENDING_FLUSH_LIST", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_PAGE_YOUNG 10
|
|
Column("PAGES_MADE_YOUNG",ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_PAGE_NOT_YOUNG 11
|
|
Column("PAGES_NOT_MADE_YOUNG",ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_PAGE_YOUNG_RATE 12
|
|
Column("PAGES_MADE_YOUNG_RATE", Float(MAX_FLOAT_STR_LENGTH), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_PAGE_NOT_YOUNG_RATE 13
|
|
Column("PAGES_MADE_NOT_YOUNG_RATE", Float(MAX_FLOAT_STR_LENGTH), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_PAGE_READ 14
|
|
Column("NUMBER_PAGES_READ",ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_PAGE_CREATED 15
|
|
Column("NUMBER_PAGES_CREATED",ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_PAGE_WRITTEN 16
|
|
Column("NUMBER_PAGES_WRITTEN",ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_PAGE_READ_RATE 17
|
|
Column("PAGES_READ_RATE", Float(MAX_FLOAT_STR_LENGTH), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_PAGE_CREATE_RATE 18
|
|
Column("PAGES_CREATE_RATE", Float(MAX_FLOAT_STR_LENGTH), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_PAGE_WRITTEN_RATE 19
|
|
Column("PAGES_WRITTEN_RATE",Float(MAX_FLOAT_STR_LENGTH), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_GET 20
|
|
Column("NUMBER_PAGES_GET", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_HIT_RATE 21
|
|
Column("HIT_RATE", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_MADE_YOUNG_PCT 22
|
|
Column("YOUNG_MAKE_PER_THOUSAND_GETS", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_NOT_MADE_YOUNG_PCT 23
|
|
Column("NOT_YOUNG_MAKE_PER_THOUSAND_GETS", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_READ_AHEAD 24
|
|
Column("NUMBER_PAGES_READ_AHEAD", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_READ_AHEAD_EVICTED 25
|
|
Column("NUMBER_READ_AHEAD_EVICTED", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_READ_AHEAD_RATE 26
|
|
Column("READ_AHEAD_RATE", Float(MAX_FLOAT_STR_LENGTH), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_READ_AHEAD_EVICT_RATE 27
|
|
Column("READ_AHEAD_EVICTED_RATE",Float(MAX_FLOAT_STR_LENGTH), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_LRU_IO_SUM 28
|
|
Column("LRU_IO_TOTAL", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_LRU_IO_CUR 29
|
|
Column("LRU_IO_CURRENT", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_UNZIP_SUM 30
|
|
Column("UNCOMPRESS_TOTAL",ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_STATS_UNZIP_CUR 31
|
|
Column("UNCOMPRESS_CURRENT", ULonglong(), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/** Fill INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STATS
|
|
@param[in,out] thd connection
|
|
@param[in,out] tables tables to fill
|
|
@return 0 on success, 1 on failure */
|
|
static int i_s_innodb_stats_fill(THD *thd, TABLE_LIST * tables, Item *)
|
|
{
|
|
TABLE* table;
|
|
Field** fields;
|
|
buf_pool_info_t info;
|
|
|
|
DBUG_ENTER("i_s_innodb_stats_fill");
|
|
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
/* Only allow the PROCESS privilege holder to access the stats */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
buf_stats_get_pool_info(&info);
|
|
|
|
table = tables->table;
|
|
|
|
fields = table->field;
|
|
|
|
OK(fields[IDX_BUF_STATS_POOL_ID]->store(0, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_POOL_SIZE]->store(info.pool_size, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_LRU_LEN]->store(info.lru_len, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_OLD_LRU_LEN]->store(info.old_lru_len, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_FREE_BUFFERS]->store(
|
|
info.free_list_len, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_FLUSH_LIST_LEN]->store(
|
|
info.flush_list_len, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_PENDING_ZIP]->store(info.n_pend_unzip, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_PENDING_READ]->store(info.n_pend_reads, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_FLUSH_LRU]->store(
|
|
info.n_pending_flush_lru, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_FLUSH_LIST]->store(
|
|
info.n_pending_flush_list, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_PAGE_YOUNG]->store(
|
|
info.n_pages_made_young, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG]->store(
|
|
info.n_pages_not_made_young, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_PAGE_YOUNG_RATE]->store(
|
|
info.page_made_young_rate));
|
|
|
|
OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG_RATE]->store(
|
|
info.page_not_made_young_rate));
|
|
|
|
OK(fields[IDX_BUF_STATS_PAGE_READ]->store(info.n_pages_read, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_PAGE_CREATED]->store(
|
|
info.n_pages_created, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_PAGE_WRITTEN]->store(
|
|
info.n_pages_written, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_GET]->store(info.n_page_gets, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_PAGE_READ_RATE]->store(
|
|
info.pages_read_rate));
|
|
|
|
OK(fields[IDX_BUF_STATS_PAGE_CREATE_RATE]->store(
|
|
info.pages_created_rate));
|
|
|
|
OK(fields[IDX_BUF_STATS_PAGE_WRITTEN_RATE]->store(
|
|
info.pages_written_rate));
|
|
|
|
if (info.n_page_get_delta) {
|
|
if (info.page_read_delta <= info.n_page_get_delta) {
|
|
OK(fields[IDX_BUF_STATS_HIT_RATE]->store(
|
|
static_cast<double>(
|
|
1000 - (1000 * info.page_read_delta
|
|
/ info.n_page_get_delta))));
|
|
} else {
|
|
OK(fields[IDX_BUF_STATS_HIT_RATE]->store(0));
|
|
}
|
|
|
|
OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(
|
|
1000 * info.young_making_delta
|
|
/ info.n_page_get_delta, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(
|
|
1000 * info.not_young_making_delta
|
|
/ info.n_page_get_delta, true));
|
|
} else {
|
|
OK(fields[IDX_BUF_STATS_HIT_RATE]->store(0, true));
|
|
OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(0, true));
|
|
OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(0, true));
|
|
}
|
|
|
|
OK(fields[IDX_BUF_STATS_READ_AHEAD]->store(
|
|
info.n_ra_pages_read, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICTED]->store(
|
|
info.n_ra_pages_evicted, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_READ_AHEAD_RATE]->store(
|
|
info.pages_readahead_rate));
|
|
|
|
OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICT_RATE]->store(
|
|
info.pages_evicted_rate));
|
|
|
|
OK(fields[IDX_BUF_STATS_LRU_IO_SUM]->store(info.io_sum, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_LRU_IO_CUR]->store(info.io_cur, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_UNZIP_SUM]->store(info.unzip_sum, true));
|
|
|
|
OK(fields[IDX_BUF_STATS_UNZIP_CUR]->store(info.unzip_cur, true));
|
|
|
|
DBUG_RETURN(schema_table_store_record(thd, table));
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STATS.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_innodb_buffer_pool_stats_init(
|
|
/*==============================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("i_s_innodb_buffer_pool_stats_init");
|
|
|
|
schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);
|
|
|
|
schema->fields_info = Show::i_s_innodb_buffer_stats_fields_info;
|
|
schema->fill_table = i_s_innodb_stats_fill;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_buffer_stats =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_BUFFER_POOL_STATS",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB Buffer Pool Statistics Information ",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_innodb_buffer_pool_stats_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
/** These must correspond to the first values of buf_page_state */
|
|
static const LEX_CSTRING page_state_values[] =
|
|
{
|
|
{ STRING_WITH_LEN("NOT_USED") },
|
|
{ STRING_WITH_LEN("MEMORY") },
|
|
{ STRING_WITH_LEN("REMOVE_HASH") },
|
|
{ STRING_WITH_LEN("FILE_PAGE") },
|
|
};
|
|
|
|
static const TypelibBuffer<4> page_state_values_typelib(page_state_values);
|
|
|
|
static const LEX_CSTRING io_values[] =
|
|
{
|
|
{ STRING_WITH_LEN("IO_NONE") },
|
|
{ STRING_WITH_LEN("IO_READ") },
|
|
{ STRING_WITH_LEN("IO_WRITE") }
|
|
};
|
|
|
|
|
|
static TypelibBuffer<3> io_values_typelib(io_values);
|
|
|
|
namespace Show {
|
|
/* Fields of the dynamic table INNODB_BUFFER_POOL_PAGE. */
|
|
static ST_FIELD_INFO i_s_innodb_buffer_page_fields_info[]=
|
|
{
|
|
#define IDX_BUFFER_POOL_ID 0
|
|
Column("POOL_ID", ULong(), NOT_NULL),
|
|
|
|
#define IDX_BUFFER_BLOCK_ID 1
|
|
Column("BLOCK_ID", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUFFER_PAGE_SPACE 2
|
|
Column("SPACE", ULong(), NOT_NULL),
|
|
|
|
#define IDX_BUFFER_PAGE_NUM 3
|
|
Column("PAGE_NUMBER", ULong(), NOT_NULL),
|
|
|
|
#define IDX_BUFFER_PAGE_TYPE 4
|
|
Column("PAGE_TYPE", Varchar(64), NULLABLE),
|
|
|
|
#define IDX_BUFFER_PAGE_FLUSH_TYPE 5
|
|
Column("FLUSH_TYPE", ULong(), NOT_NULL),
|
|
|
|
#define IDX_BUFFER_PAGE_FIX_COUNT 6
|
|
Column("FIX_COUNT", ULong(), NOT_NULL),
|
|
|
|
#ifdef BTR_CUR_HASH_ADAPT
|
|
#define IDX_BUFFER_PAGE_HASHED 7
|
|
Column("IS_HASHED", SLong(1), NOT_NULL),
|
|
#endif /* BTR_CUR_HASH_ADAPT */
|
|
#define IDX_BUFFER_PAGE_NEWEST_MOD 7 + I_S_AHI
|
|
Column("NEWEST_MODIFICATION", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUFFER_PAGE_OLDEST_MOD 8 + I_S_AHI
|
|
Column("OLDEST_MODIFICATION", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUFFER_PAGE_ACCESS_TIME 9 + I_S_AHI
|
|
Column("ACCESS_TIME", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUFFER_PAGE_TABLE_NAME 10 + I_S_AHI
|
|
Column("TABLE_NAME", Varchar(1024), NULLABLE),
|
|
|
|
#define IDX_BUFFER_PAGE_INDEX_NAME 11 + I_S_AHI
|
|
Column("INDEX_NAME", Varchar(NAME_CHAR_LEN), NULLABLE),
|
|
|
|
#define IDX_BUFFER_PAGE_NUM_RECS 12 + I_S_AHI
|
|
Column("NUMBER_RECORDS", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUFFER_PAGE_DATA_SIZE 13 + I_S_AHI
|
|
Column("DATA_SIZE", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUFFER_PAGE_ZIP_SIZE 14 + I_S_AHI
|
|
Column("COMPRESSED_SIZE", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUFFER_PAGE_STATE 15 + I_S_AHI
|
|
Column("PAGE_STATE", Enum(&page_state_values_typelib), NOT_NULL),
|
|
|
|
#define IDX_BUFFER_PAGE_IO_FIX 16 + I_S_AHI
|
|
Column("IO_FIX", Enum(&io_values_typelib), NOT_NULL),
|
|
|
|
#define IDX_BUFFER_PAGE_IS_OLD 17 + I_S_AHI
|
|
Column("IS_OLD", SLong(1), NOT_NULL),
|
|
|
|
#define IDX_BUFFER_PAGE_FREE_CLOCK 18 + I_S_AHI
|
|
Column("FREE_PAGE_CLOCK", ULonglong(), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/*******************************************************************//**
|
|
Fill Information Schema table INNODB_BUFFER_PAGE with information
|
|
cached in the buf_page_info_t array
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_innodb_buffer_page_fill(
|
|
/*========================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
const buf_page_info_t* info_array, /*!< in: array cached page
|
|
info */
|
|
ulint num_page) /*!< in: number of page info
|
|
cached */
|
|
{
|
|
TABLE* table;
|
|
Field** fields;
|
|
|
|
compile_time_assert(I_S_PAGE_TYPE_LAST < 1 << I_S_PAGE_TYPE_BITS);
|
|
|
|
DBUG_ENTER("i_s_innodb_buffer_page_fill");
|
|
|
|
table = tables->table;
|
|
|
|
fields = table->field;
|
|
|
|
/* Iterate through the cached array and fill the I_S table rows */
|
|
for (ulint i = 0; i < num_page; i++) {
|
|
const buf_page_info_t* page_info;
|
|
char table_name[MAX_FULL_NAME_LEN + 1];
|
|
const char* table_name_end = NULL;
|
|
|
|
page_info = info_array + i;
|
|
|
|
OK(fields[IDX_BUFFER_POOL_ID]->store(0, true));
|
|
|
|
OK(fields[IDX_BUFFER_BLOCK_ID]->store(
|
|
page_info->block_id, true));
|
|
|
|
OK(fields[IDX_BUFFER_PAGE_SPACE]->store(
|
|
page_info->id.space(), true));
|
|
|
|
OK(fields[IDX_BUFFER_PAGE_NUM]->store(
|
|
page_info->id.page_no(), true));
|
|
|
|
OK(field_store_string(
|
|
fields[IDX_BUFFER_PAGE_TYPE],
|
|
i_s_page_type[page_info->page_type].type_str));
|
|
|
|
OK(fields[IDX_BUFFER_PAGE_FLUSH_TYPE]->store(0, true));
|
|
|
|
OK(fields[IDX_BUFFER_PAGE_FIX_COUNT]->store(
|
|
~buf_page_t::LRU_MASK & page_info->state, true));
|
|
|
|
#ifdef BTR_CUR_HASH_ADAPT
|
|
OK(fields[IDX_BUFFER_PAGE_HASHED]->store(
|
|
page_info->hashed, true));
|
|
#endif /* BTR_CUR_HASH_ADAPT */
|
|
|
|
OK(fields[IDX_BUFFER_PAGE_NEWEST_MOD]->store(
|
|
page_info->newest_mod, true));
|
|
|
|
OK(fields[IDX_BUFFER_PAGE_OLDEST_MOD]->store(
|
|
page_info->oldest_mod, true));
|
|
|
|
OK(fields[IDX_BUFFER_PAGE_ACCESS_TIME]->store(
|
|
page_info->access_time, true));
|
|
|
|
fields[IDX_BUFFER_PAGE_TABLE_NAME]->set_null();
|
|
|
|
fields[IDX_BUFFER_PAGE_INDEX_NAME]->set_null();
|
|
|
|
/* If this is an index page, fetch the index name
|
|
and table name */
|
|
if (page_info->page_type == I_S_PAGE_TYPE_INDEX) {
|
|
bool ret = false;
|
|
|
|
dict_sys.freeze(SRW_LOCK_CALL);
|
|
|
|
const dict_index_t* index =
|
|
dict_index_get_if_in_cache_low(
|
|
page_info->index_id);
|
|
|
|
if (index) {
|
|
table_name_end = innobase_convert_name(
|
|
table_name, sizeof(table_name),
|
|
index->table->name.m_name,
|
|
strlen(index->table->name.m_name),
|
|
thd);
|
|
|
|
ret = fields[IDX_BUFFER_PAGE_TABLE_NAME]
|
|
->store(table_name,
|
|
static_cast<uint>(
|
|
table_name_end
|
|
- table_name),
|
|
system_charset_info)
|
|
|| fields[IDX_BUFFER_PAGE_INDEX_NAME]
|
|
->store(index->name,
|
|
uint(strlen(index->name)),
|
|
system_charset_info);
|
|
}
|
|
|
|
dict_sys.unfreeze();
|
|
|
|
OK(ret);
|
|
|
|
if (index) {
|
|
fields[IDX_BUFFER_PAGE_TABLE_NAME]
|
|
->set_notnull();
|
|
fields[IDX_BUFFER_PAGE_INDEX_NAME]
|
|
->set_notnull();
|
|
}
|
|
}
|
|
|
|
OK(fields[IDX_BUFFER_PAGE_NUM_RECS]->store(
|
|
page_info->num_recs, true));
|
|
|
|
OK(fields[IDX_BUFFER_PAGE_DATA_SIZE]->store(
|
|
page_info->data_size, true));
|
|
|
|
OK(fields[IDX_BUFFER_PAGE_ZIP_SIZE]->store(
|
|
page_info->zip_ssize
|
|
? (UNIV_ZIP_SIZE_MIN >> 1) << page_info->zip_ssize
|
|
: 0, true));
|
|
|
|
static_assert(buf_page_t::NOT_USED == 0, "compatibility");
|
|
static_assert(buf_page_t::MEMORY == 1, "compatibility");
|
|
static_assert(buf_page_t::REMOVE_HASH == 2, "compatibility");
|
|
|
|
OK(fields[IDX_BUFFER_PAGE_STATE]->store(
|
|
std::min<uint32_t>(3, page_info->state) + 1, true));
|
|
|
|
static_assert(buf_page_t::UNFIXED == 2U << 29, "comp.");
|
|
static_assert(buf_page_t::READ_FIX == 4U << 29, "comp.");
|
|
static_assert(buf_page_t::WRITE_FIX == 6U << 29, "comp.");
|
|
|
|
unsigned io_fix = page_info->state >> 29;
|
|
if (io_fix < 4) {
|
|
io_fix = 1;
|
|
} else if (io_fix == 4) {
|
|
io_fix = 2;
|
|
} else {
|
|
io_fix = 3;
|
|
}
|
|
|
|
OK(fields[IDX_BUFFER_PAGE_IO_FIX]->store(io_fix, true));
|
|
|
|
OK(fields[IDX_BUFFER_PAGE_IS_OLD]->store(
|
|
page_info->is_old, true));
|
|
|
|
OK(fields[IDX_BUFFER_PAGE_FREE_CLOCK]->store(
|
|
page_info->freed_page_clock, true));
|
|
|
|
OK(schema_table_store_record(thd, table));
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Set appropriate page type to a buf_page_info_t structure */
|
|
static
|
|
void
|
|
i_s_innodb_set_page_type(
|
|
/*=====================*/
|
|
buf_page_info_t*page_info, /*!< in/out: structure to fill with
|
|
scanned info */
|
|
const byte* frame) /*!< in: buffer frame */
|
|
{
|
|
uint16_t page_type = fil_page_get_type(frame);
|
|
|
|
if (fil_page_type_is_index(page_type)) {
|
|
const page_t* page = (const page_t*) frame;
|
|
|
|
page_info->index_id = btr_page_get_index_id(page);
|
|
|
|
/* FIL_PAGE_INDEX and FIL_PAGE_RTREE are a bit special,
|
|
their values are defined as 17855 and 17854, so we cannot
|
|
use them to index into i_s_page_type[] array, its array index
|
|
in the i_s_page_type[] array is I_S_PAGE_TYPE_INDEX
|
|
(1) for index pages */
|
|
if (page_type == FIL_PAGE_RTREE) {
|
|
page_info->page_type = I_S_PAGE_TYPE_RTREE;
|
|
} else {
|
|
ut_ad(page_type == FIL_PAGE_INDEX
|
|
|| page_type == FIL_PAGE_TYPE_INSTANT);
|
|
page_info->page_type = I_S_PAGE_TYPE_INDEX;
|
|
}
|
|
|
|
page_info->data_size = uint16_t(page_header_get_field(
|
|
page, PAGE_HEAP_TOP) - (page_is_comp(page)
|
|
? PAGE_NEW_SUPREMUM_END
|
|
: PAGE_OLD_SUPREMUM_END)
|
|
- page_header_get_field(page, PAGE_GARBAGE));
|
|
|
|
page_info->num_recs = page_get_n_recs(page) & ((1U << 14) - 1);
|
|
} else if (page_type > FIL_PAGE_TYPE_LAST) {
|
|
/* Encountered an unknown page type */
|
|
page_info->page_type = I_S_PAGE_TYPE_UNKNOWN;
|
|
} else {
|
|
/* Make sure we get the right index into the
|
|
i_s_page_type[] array */
|
|
ut_a(page_type == i_s_page_type[page_type].type_value);
|
|
|
|
page_info->page_type = page_type & 0xf;
|
|
}
|
|
}
|
|
/*******************************************************************//**
|
|
Scans pages in the buffer cache, and collect their general information
|
|
into the buf_page_info_t array which is zero-filled. So any fields
|
|
that are not initialized in the function will default to 0 */
|
|
static
|
|
void
|
|
i_s_innodb_buffer_page_get_info(
|
|
/*============================*/
|
|
const buf_page_t*bpage, /*!< in: buffer pool page to scan */
|
|
ulint pos, /*!< in: buffer block position in
|
|
buffer pool or in the LRU list */
|
|
buf_page_info_t*page_info) /*!< in: zero filled info structure;
|
|
out: structure filled with scanned
|
|
info */
|
|
{
|
|
page_info->block_id = pos;
|
|
|
|
static_assert(buf_page_t::NOT_USED == 0, "compatibility");
|
|
static_assert(buf_page_t::MEMORY == 1, "compatibility");
|
|
static_assert(buf_page_t::REMOVE_HASH == 2, "compatibility");
|
|
static_assert(buf_page_t::UNFIXED == 2U << 29, "compatibility");
|
|
static_assert(buf_page_t::READ_FIX == 4U << 29, "compatibility");
|
|
static_assert(buf_page_t::WRITE_FIX == 6U << 29, "compatibility");
|
|
|
|
page_info->state = bpage->state();
|
|
|
|
if (page_info->state < buf_page_t::UNFIXED) {
|
|
page_info->page_type = I_S_PAGE_TYPE_UNKNOWN;
|
|
page_info->compressed_only = false;
|
|
} else {
|
|
const byte* frame;
|
|
|
|
page_info->id = bpage->id();
|
|
|
|
page_info->oldest_mod = bpage->oldest_modification();
|
|
|
|
page_info->access_time = bpage->access_time;
|
|
|
|
page_info->zip_ssize = bpage->zip.ssize;
|
|
|
|
page_info->is_old = bpage->old;
|
|
|
|
page_info->freed_page_clock = bpage->freed_page_clock;
|
|
|
|
if (page_info->state >= buf_page_t::READ_FIX
|
|
&& page_info->state < buf_page_t::WRITE_FIX) {
|
|
page_info->page_type = I_S_PAGE_TYPE_UNKNOWN;
|
|
page_info->newest_mod = 0;
|
|
return;
|
|
}
|
|
|
|
page_info->compressed_only = !bpage->frame,
|
|
frame = bpage->frame;
|
|
if (UNIV_LIKELY(frame != nullptr)) {
|
|
#ifdef BTR_CUR_HASH_ADAPT
|
|
/* Note: this may be a false positive, that
|
|
is, block->index will not always be set to
|
|
NULL when the last adaptive hash index
|
|
reference is dropped. */
|
|
page_info->hashed =
|
|
reinterpret_cast<const buf_block_t*>(bpage)
|
|
->index != nullptr;
|
|
#endif /* BTR_CUR_HASH_ADAPT */
|
|
} else {
|
|
ut_ad(page_info->zip_ssize);
|
|
frame = bpage->zip.data;
|
|
}
|
|
|
|
page_info->newest_mod = mach_read_from_8(FIL_PAGE_LSN + frame);
|
|
i_s_innodb_set_page_type(page_info, frame);
|
|
}
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
This is the function that goes through each block of the buffer pool
|
|
and fetch information to information schema tables: INNODB_BUFFER_PAGE.
|
|
@param[in,out] thd connection
|
|
@param[in,out] tables tables to fill
|
|
@return 0 on success, 1 on failure */
|
|
static int i_s_innodb_buffer_page_fill(THD *thd, TABLE_LIST *tables, Item *)
|
|
{
|
|
int status = 0;
|
|
mem_heap_t* heap;
|
|
|
|
DBUG_ENTER("i_s_innodb_buffer_page_fill");
|
|
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
/* deny access to user without PROCESS privilege */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
heap = mem_heap_create(10000);
|
|
|
|
for (ulint n = 0;
|
|
n < ut_min(buf_pool.n_chunks, buf_pool.n_chunks_new); n++) {
|
|
const buf_block_t* block;
|
|
ulint n_blocks;
|
|
buf_page_info_t* info_buffer;
|
|
ulint num_page;
|
|
ulint mem_size;
|
|
ulint chunk_size;
|
|
ulint num_to_process = 0;
|
|
ulint block_id = 0;
|
|
|
|
/* Get buffer block of the nth chunk */
|
|
block = buf_pool.chunks[n].blocks;
|
|
chunk_size = buf_pool.chunks[n].size;
|
|
num_page = 0;
|
|
|
|
while (chunk_size > 0) {
|
|
/* we cache maximum MAX_BUF_INFO_CACHED number of
|
|
buffer page info */
|
|
num_to_process = ut_min(chunk_size,
|
|
(ulint)MAX_BUF_INFO_CACHED);
|
|
|
|
mem_size = num_to_process * sizeof(buf_page_info_t);
|
|
|
|
/* For each chunk, we'll pre-allocate information
|
|
structures to cache the page information read from
|
|
the buffer pool. Doing so before obtain any mutex */
|
|
info_buffer = (buf_page_info_t*) mem_heap_zalloc(
|
|
heap, mem_size);
|
|
|
|
/* Obtain appropriate mutexes. Since this is diagnostic
|
|
buffer pool info printout, we are not required to
|
|
preserve the overall consistency, so we can
|
|
release mutex periodically */
|
|
mysql_mutex_lock(&buf_pool.mutex);
|
|
|
|
/* GO through each block in the chunk */
|
|
for (n_blocks = num_to_process; n_blocks--; block++) {
|
|
i_s_innodb_buffer_page_get_info(
|
|
&block->page, block_id,
|
|
info_buffer + num_page);
|
|
block_id++;
|
|
num_page++;
|
|
}
|
|
|
|
mysql_mutex_unlock(&buf_pool.mutex);
|
|
|
|
/* Fill in information schema table with information
|
|
just collected from the buffer chunk scan */
|
|
status = i_s_innodb_buffer_page_fill(
|
|
thd, tables, info_buffer,
|
|
num_page);
|
|
|
|
/* If something goes wrong, break and return */
|
|
if (status) {
|
|
break;
|
|
}
|
|
|
|
mem_heap_empty(heap);
|
|
chunk_size -= num_to_process;
|
|
num_page = 0;
|
|
}
|
|
}
|
|
|
|
mem_heap_free(heap);
|
|
|
|
DBUG_RETURN(status);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_innodb_buffer_page_init(
|
|
/*========================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("i_s_innodb_buffer_page_init");
|
|
|
|
schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);
|
|
|
|
schema->fields_info = Show::i_s_innodb_buffer_page_fields_info;
|
|
schema->fill_table = i_s_innodb_buffer_page_fill;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_buffer_page =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_BUFFER_PAGE",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB Buffer Page Information",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_innodb_buffer_page_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
namespace Show {
|
|
static ST_FIELD_INFO i_s_innodb_buf_page_lru_fields_info[] =
|
|
{
|
|
#define IDX_BUF_LRU_POOL_ID 0
|
|
Column("POOL_ID", ULong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_LRU_POS 1
|
|
Column("LRU_POSITION", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_LRU_PAGE_SPACE 2
|
|
Column("SPACE", ULong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_LRU_PAGE_NUM 3
|
|
Column("PAGE_NUMBER", ULong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_LRU_PAGE_TYPE 4
|
|
Column("PAGE_TYPE", Varchar(64), NULLABLE),
|
|
|
|
#define IDX_BUF_LRU_PAGE_FLUSH_TYPE 5
|
|
Column("FLUSH_TYPE", ULong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_LRU_PAGE_FIX_COUNT 6
|
|
Column("FIX_COUNT", ULong(), NOT_NULL),
|
|
|
|
#ifdef BTR_CUR_HASH_ADAPT
|
|
#define IDX_BUF_LRU_PAGE_HASHED 7
|
|
Column("IS_HASHED", SLong(1), NOT_NULL),
|
|
#endif /* BTR_CUR_HASH_ADAPT */
|
|
#define IDX_BUF_LRU_PAGE_NEWEST_MOD 7 + I_S_AHI
|
|
Column("NEWEST_MODIFICATION",ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_LRU_PAGE_OLDEST_MOD 8 + I_S_AHI
|
|
Column("OLDEST_MODIFICATION",ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_LRU_PAGE_ACCESS_TIME 9 + I_S_AHI
|
|
Column("ACCESS_TIME",ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_LRU_PAGE_TABLE_NAME 10 + I_S_AHI
|
|
Column("TABLE_NAME", Varchar(1024), NULLABLE),
|
|
|
|
#define IDX_BUF_LRU_PAGE_INDEX_NAME 11 + I_S_AHI
|
|
Column("INDEX_NAME", Varchar(NAME_CHAR_LEN), NULLABLE),
|
|
|
|
#define IDX_BUF_LRU_PAGE_NUM_RECS 12 + I_S_AHI
|
|
Column("NUMBER_RECORDS", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_LRU_PAGE_DATA_SIZE 13 + I_S_AHI
|
|
Column("DATA_SIZE", ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_LRU_PAGE_ZIP_SIZE 14 + I_S_AHI
|
|
Column("COMPRESSED_SIZE",ULonglong(), NOT_NULL),
|
|
|
|
#define IDX_BUF_LRU_PAGE_STATE 15 + I_S_AHI
|
|
Column("COMPRESSED", SLong(1), NOT_NULL),
|
|
|
|
#define IDX_BUF_LRU_PAGE_IO_FIX 16 + I_S_AHI
|
|
Column("IO_FIX", Enum(&io_values_typelib), NOT_NULL),
|
|
|
|
#define IDX_BUF_LRU_PAGE_IS_OLD 17 + I_S_AHI
|
|
Column("IS_OLD", SLong(1), NULLABLE),
|
|
|
|
#define IDX_BUF_LRU_PAGE_FREE_CLOCK 18 + I_S_AHI
|
|
Column("FREE_PAGE_CLOCK", ULonglong(), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/*******************************************************************//**
|
|
Fill Information Schema table INNODB_BUFFER_PAGE_LRU with information
|
|
cached in the buf_page_info_t array
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_innodb_buf_page_lru_fill(
|
|
/*=========================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
const buf_page_info_t* info_array, /*!< in: array cached page
|
|
info */
|
|
ulint num_page) /*!< in: number of page info
|
|
cached */
|
|
{
|
|
DBUG_ENTER("i_s_innodb_buf_page_lru_fill");
|
|
|
|
TABLE* table = tables->table;
|
|
Field** fields = table->field;
|
|
|
|
/* Iterate through the cached array and fill the I_S table rows */
|
|
for (ulint i = 0; i < num_page; i++) {
|
|
const buf_page_info_t* page_info;
|
|
char table_name[MAX_FULL_NAME_LEN + 1];
|
|
const char* table_name_end = NULL;
|
|
|
|
page_info = info_array + i;
|
|
|
|
OK(fields[IDX_BUF_LRU_POOL_ID]->store(0, true));
|
|
|
|
OK(fields[IDX_BUF_LRU_POS]->store(
|
|
page_info->block_id, true));
|
|
|
|
OK(fields[IDX_BUF_LRU_PAGE_SPACE]->store(
|
|
page_info->id.space(), true));
|
|
|
|
OK(fields[IDX_BUF_LRU_PAGE_NUM]->store(
|
|
page_info->id.page_no(), true));
|
|
|
|
OK(field_store_string(
|
|
fields[IDX_BUF_LRU_PAGE_TYPE],
|
|
i_s_page_type[page_info->page_type].type_str));
|
|
|
|
OK(fields[IDX_BUF_LRU_PAGE_FLUSH_TYPE]->store(0, true));
|
|
|
|
OK(fields[IDX_BUF_LRU_PAGE_FIX_COUNT]->store(
|
|
~buf_page_t::LRU_MASK & page_info->state, true));
|
|
|
|
#ifdef BTR_CUR_HASH_ADAPT
|
|
OK(fields[IDX_BUF_LRU_PAGE_HASHED]->store(
|
|
page_info->hashed, true));
|
|
#endif /* BTR_CUR_HASH_ADAPT */
|
|
|
|
OK(fields[IDX_BUF_LRU_PAGE_NEWEST_MOD]->store(
|
|
page_info->newest_mod, true));
|
|
|
|
OK(fields[IDX_BUF_LRU_PAGE_OLDEST_MOD]->store(
|
|
page_info->oldest_mod, true));
|
|
|
|
OK(fields[IDX_BUF_LRU_PAGE_ACCESS_TIME]->store(
|
|
page_info->access_time, true));
|
|
|
|
fields[IDX_BUF_LRU_PAGE_TABLE_NAME]->set_null();
|
|
|
|
fields[IDX_BUF_LRU_PAGE_INDEX_NAME]->set_null();
|
|
|
|
/* If this is an index page, fetch the index name
|
|
and table name */
|
|
if (page_info->page_type == I_S_PAGE_TYPE_INDEX) {
|
|
bool ret = false;
|
|
|
|
dict_sys.freeze(SRW_LOCK_CALL);
|
|
|
|
const dict_index_t* index =
|
|
dict_index_get_if_in_cache_low(
|
|
page_info->index_id);
|
|
|
|
if (index) {
|
|
table_name_end = innobase_convert_name(
|
|
table_name, sizeof(table_name),
|
|
index->table->name.m_name,
|
|
strlen(index->table->name.m_name),
|
|
thd);
|
|
|
|
ret = fields[IDX_BUF_LRU_PAGE_TABLE_NAME]
|
|
->store(table_name,
|
|
static_cast<uint>(
|
|
table_name_end
|
|
- table_name),
|
|
system_charset_info)
|
|
|| fields[IDX_BUF_LRU_PAGE_INDEX_NAME]
|
|
->store(index->name,
|
|
uint(strlen(index->name)),
|
|
system_charset_info);
|
|
}
|
|
|
|
dict_sys.unfreeze();
|
|
|
|
OK(ret);
|
|
|
|
if (index) {
|
|
fields[IDX_BUF_LRU_PAGE_TABLE_NAME]
|
|
->set_notnull();
|
|
fields[IDX_BUF_LRU_PAGE_INDEX_NAME]
|
|
->set_notnull();
|
|
}
|
|
}
|
|
|
|
OK(fields[IDX_BUF_LRU_PAGE_NUM_RECS]->store(
|
|
page_info->num_recs, true));
|
|
|
|
OK(fields[IDX_BUF_LRU_PAGE_DATA_SIZE]->store(
|
|
page_info->data_size, true));
|
|
|
|
OK(fields[IDX_BUF_LRU_PAGE_ZIP_SIZE]->store(
|
|
page_info->zip_ssize
|
|
? 512 << page_info->zip_ssize : 0, true));
|
|
|
|
OK(fields[IDX_BUF_LRU_PAGE_STATE]->store(
|
|
page_info->compressed_only, true));
|
|
|
|
static_assert(buf_page_t::UNFIXED == 2U << 29, "comp.");
|
|
static_assert(buf_page_t::READ_FIX == 4U << 29, "comp.");
|
|
static_assert(buf_page_t::WRITE_FIX == 6U << 29, "comp.");
|
|
|
|
unsigned io_fix = page_info->state >> 29;
|
|
if (io_fix < 4) {
|
|
io_fix = 1;
|
|
} else if (io_fix == 4) {
|
|
io_fix = 2;
|
|
} else {
|
|
io_fix = 3;
|
|
}
|
|
|
|
OK(fields[IDX_BUF_LRU_PAGE_IO_FIX]->store(io_fix, true));
|
|
|
|
OK(fields[IDX_BUF_LRU_PAGE_IS_OLD]->store(
|
|
page_info->is_old, true));
|
|
|
|
OK(fields[IDX_BUF_LRU_PAGE_FREE_CLOCK]->store(
|
|
page_info->freed_page_clock, true));
|
|
|
|
OK(schema_table_store_record(thd, table));
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/** Fill the table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU.
|
|
@param[in] thd thread
|
|
@param[in,out] tables tables to fill
|
|
@return 0 on success, 1 on failure */
|
|
static int i_s_innodb_fill_buffer_lru(THD *thd, TABLE_LIST *tables, Item *)
|
|
{
|
|
int status = 0;
|
|
buf_page_info_t* info_buffer;
|
|
ulint lru_pos = 0;
|
|
const buf_page_t* bpage;
|
|
ulint lru_len;
|
|
|
|
DBUG_ENTER("i_s_innodb_fill_buffer_lru");
|
|
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
/* deny access to any users that do not hold PROCESS_ACL */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/* Aquire the mutex before allocating info_buffer, since
|
|
UT_LIST_GET_LEN(buf_pool.LRU) could change */
|
|
mysql_mutex_lock(&buf_pool.mutex);
|
|
|
|
lru_len = UT_LIST_GET_LEN(buf_pool.LRU);
|
|
|
|
/* Print error message if malloc fail */
|
|
info_buffer = (buf_page_info_t*) my_malloc(PSI_INSTRUMENT_ME,
|
|
lru_len * sizeof *info_buffer, MYF(MY_WME | MY_ZEROFILL));
|
|
|
|
if (!info_buffer) {
|
|
status = 1;
|
|
goto exit;
|
|
}
|
|
|
|
/* Walk through Pool's LRU list and print the buffer page
|
|
information */
|
|
bpage = UT_LIST_GET_LAST(buf_pool.LRU);
|
|
|
|
while (bpage != NULL) {
|
|
/* Use the same function that collect buffer info for
|
|
INNODB_BUFFER_PAGE to get buffer page info */
|
|
i_s_innodb_buffer_page_get_info(bpage, lru_pos,
|
|
(info_buffer + lru_pos));
|
|
|
|
bpage = UT_LIST_GET_PREV(LRU, bpage);
|
|
|
|
lru_pos++;
|
|
}
|
|
|
|
ut_ad(lru_pos == lru_len);
|
|
ut_ad(lru_pos == UT_LIST_GET_LEN(buf_pool.LRU));
|
|
|
|
exit:
|
|
mysql_mutex_unlock(&buf_pool.mutex);
|
|
|
|
if (info_buffer) {
|
|
status = i_s_innodb_buf_page_lru_fill(
|
|
thd, tables, info_buffer, lru_len);
|
|
|
|
my_free(info_buffer);
|
|
}
|
|
|
|
DBUG_RETURN(status);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU.
|
|
@return 0 on success, 1 on failure */
|
|
static
|
|
int
|
|
i_s_innodb_buffer_page_lru_init(
|
|
/*============================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("i_s_innodb_buffer_page_lru_init");
|
|
|
|
schema = reinterpret_cast<ST_SCHEMA_TABLE*>(p);
|
|
|
|
schema->fields_info = Show::i_s_innodb_buf_page_lru_fields_info;
|
|
schema->fill_table = i_s_innodb_fill_buffer_lru;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_buffer_page_lru =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_BUFFER_PAGE_LRU",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB Buffer Page in LRU",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
i_s_innodb_buffer_page_lru_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
/*******************************************************************//**
|
|
Unbind a dynamic INFORMATION_SCHEMA table.
|
|
@return 0 */
|
|
static int i_s_common_deinit(void*)
|
|
{
|
|
DBUG_ENTER("i_s_common_deinit");
|
|
|
|
/* Do nothing */
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
static const LEX_CSTRING row_format_values[] =
|
|
{
|
|
{ STRING_WITH_LEN("Redundant") },
|
|
{ STRING_WITH_LEN("Compact") },
|
|
{ STRING_WITH_LEN("Compressed") },
|
|
{ STRING_WITH_LEN("Dynamic") }
|
|
};
|
|
|
|
static TypelibBuffer<4> row_format_values_typelib(row_format_values);
|
|
|
|
static const LEX_CSTRING space_type_values[] =
|
|
{
|
|
{ STRING_WITH_LEN("Single") },
|
|
{ STRING_WITH_LEN("System") }
|
|
};
|
|
|
|
static TypelibBuffer<2> space_type_values_typelib(space_type_values);
|
|
|
|
namespace Show {
|
|
/** SYS_TABLES ***************************************************/
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLES */
|
|
static ST_FIELD_INFO innodb_sys_tables_fields_info[]=
|
|
{
|
|
#define SYS_TABLES_ID 0
|
|
Column("TABLE_ID", ULonglong(), NOT_NULL),
|
|
|
|
#define SYS_TABLES_NAME 1
|
|
Column("NAME", Varchar(MAX_FULL_NAME_LEN + 1), NOT_NULL),
|
|
|
|
#define SYS_TABLES_FLAG 2
|
|
Column("FLAG", SLong(), NOT_NULL),
|
|
|
|
#define SYS_TABLES_NUM_COLUMN 3
|
|
Column("N_COLS", ULong(), NOT_NULL),
|
|
|
|
#define SYS_TABLES_SPACE 4
|
|
Column("SPACE", ULong(), NOT_NULL),
|
|
|
|
#define SYS_TABLES_ROW_FORMAT 5
|
|
Column("ROW_FORMAT", Enum(&row_format_values_typelib), NULLABLE),
|
|
|
|
#define SYS_TABLES_ZIP_PAGE_SIZE 6
|
|
Column("ZIP_PAGE_SIZE", ULong(), NOT_NULL),
|
|
|
|
#define SYS_TABLES_SPACE_TYPE 7
|
|
Column("SPACE_TYPE", Enum(&space_type_values_typelib), NULLABLE),
|
|
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/**********************************************************************//**
|
|
Populate information_schema.innodb_sys_tables table with information
|
|
from SYS_TABLES.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_dict_fill_sys_tables(
|
|
/*=====================*/
|
|
THD* thd, /*!< in: thread */
|
|
dict_table_t* table, /*!< in: table */
|
|
TABLE* table_to_fill) /*!< in/out: fill this table */
|
|
{
|
|
Field** fields;
|
|
ulint compact = DICT_TF_GET_COMPACT(table->flags);
|
|
ulint atomic_blobs = DICT_TF_HAS_ATOMIC_BLOBS(
|
|
table->flags);
|
|
const ulint zip_size = dict_tf_get_zip_size(table->flags);
|
|
const char* row_format;
|
|
|
|
if (!compact) {
|
|
row_format = "Redundant";
|
|
} else if (!atomic_blobs) {
|
|
row_format = "Compact";
|
|
} else if (DICT_TF_GET_ZIP_SSIZE(table->flags)) {
|
|
row_format = "Compressed";
|
|
} else {
|
|
row_format = "Dynamic";
|
|
}
|
|
|
|
DBUG_ENTER("i_s_dict_fill_sys_tables");
|
|
|
|
fields = table_to_fill->field;
|
|
|
|
OK(fields[SYS_TABLES_ID]->store(longlong(table->id), TRUE));
|
|
|
|
OK(field_store_string(fields[SYS_TABLES_NAME], table->name.m_name));
|
|
|
|
OK(fields[SYS_TABLES_FLAG]->store(table->flags));
|
|
|
|
OK(fields[SYS_TABLES_NUM_COLUMN]->store(table->n_cols));
|
|
|
|
OK(fields[SYS_TABLES_SPACE]->store(table->space_id, true));
|
|
|
|
OK(field_store_string(fields[SYS_TABLES_ROW_FORMAT], row_format));
|
|
|
|
OK(fields[SYS_TABLES_ZIP_PAGE_SIZE]->store(zip_size, true));
|
|
|
|
OK(field_store_string(fields[SYS_TABLES_SPACE_TYPE],
|
|
table->space_id ? "Single" : "System"));
|
|
|
|
OK(schema_table_store_record(thd, table_to_fill));
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/** Handle the error for information schema query
|
|
@param err error value
|
|
@param thd thread
|
|
@return 0 if query is interrupted or error */
|
|
static int i_s_sys_error_handling(int err, THD *thd)
|
|
{
|
|
return thd_kill_level(thd) ? 0 : err;
|
|
}
|
|
|
|
/** Convert one SYS_TABLES record to dict_table_t.
|
|
@param pcur persistent cursor position on SYS_TABLES record
|
|
@param mtr mini-transaction (nullptr=use the dict_sys cache)
|
|
@param rec record to read from (nullptr=use the dict_sys cache)
|
|
@param table the converted dict_table_t
|
|
@return error message
|
|
@retval nullptr on success */
|
|
static const char *i_s_sys_tables_rec(const btr_pcur_t &pcur, mtr_t *mtr,
|
|
const rec_t *rec, dict_table_t **table)
|
|
{
|
|
static_assert(DICT_FLD__SYS_TABLES__NAME == 0, "compatibility");
|
|
size_t len;
|
|
if (rec_get_1byte_offs_flag(pcur.old_rec))
|
|
{
|
|
len= rec_1_get_field_end_info(pcur.old_rec, 0);
|
|
if (len & REC_1BYTE_SQL_NULL_MASK)
|
|
return "corrupted SYS_TABLES.NAME";
|
|
}
|
|
else
|
|
{
|
|
len= rec_2_get_field_end_info(pcur.old_rec, 0);
|
|
static_assert(REC_2BYTE_EXTERN_MASK == 16384, "compatibility");
|
|
if (len >= REC_2BYTE_EXTERN_MASK)
|
|
return "corrupted SYS_TABLES.NAME";
|
|
}
|
|
|
|
if (rec)
|
|
return dict_load_table_low(mtr, false, rec, table);
|
|
|
|
*table= dict_sys.load_table
|
|
(span<const char>{reinterpret_cast<const char*>(pcur.old_rec), len});
|
|
return *table ? nullptr : "Table not found in cache";
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Function to go through each record in SYS_TABLES table, and fill the
|
|
information_schema.innodb_sys_tables table with related table information
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_sys_tables_fill_table(
|
|
/*======================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (not used) */
|
|
{
|
|
btr_pcur_t pcur;
|
|
mtr_t mtr;
|
|
int err = 0;
|
|
|
|
DBUG_ENTER("i_s_sys_tables_fill_table");
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
/* deny access to user without PROCESS_ACL privilege */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
mtr.start();
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
|
|
for (const rec_t *rec = dict_startscan_system(&pcur, &mtr,
|
|
dict_sys.sys_tables);
|
|
rec; rec = dict_getnext_system(&pcur, &mtr)) {
|
|
if (rec_get_deleted_flag(rec, 0)) {
|
|
continue;
|
|
}
|
|
|
|
const char* err_msg;
|
|
dict_table_t* table_rec;
|
|
|
|
/* Create and populate a dict_table_t structure with
|
|
information from SYS_TABLES row */
|
|
err_msg = i_s_sys_tables_rec(pcur, &mtr, rec, &table_rec);
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
|
|
if (!err_msg) {
|
|
err = i_s_dict_fill_sys_tables(
|
|
thd, table_rec, tables->table);
|
|
if (err) {
|
|
err = i_s_sys_error_handling(err, thd);
|
|
if (table_rec) {
|
|
dict_mem_table_free(table_rec);
|
|
}
|
|
goto func_exit;
|
|
}
|
|
} else {
|
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
|
ER_CANT_FIND_SYSTEM_REC, "%s",
|
|
err_msg);
|
|
}
|
|
|
|
if (table_rec) {
|
|
dict_mem_table_free(table_rec);
|
|
}
|
|
|
|
/* Get the next record */
|
|
mtr.start();
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
}
|
|
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
func_exit:
|
|
ut_free(pcur.old_rec_buf);
|
|
|
|
DBUG_RETURN(err);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_tables
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
innodb_sys_tables_init(
|
|
/*===================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("innodb_sys_tables_init");
|
|
|
|
schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::innodb_sys_tables_fields_info;
|
|
schema->fill_table = i_s_sys_tables_fill_table;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_sys_tables =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_SYS_TABLES",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB SYS_TABLES",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
innodb_sys_tables_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
namespace Show {
|
|
/** SYS_TABLESTATS ***********************************************/
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLESTATS */
|
|
static ST_FIELD_INFO innodb_sys_tablestats_fields_info[]=
|
|
{
|
|
#define SYS_TABLESTATS_ID 0
|
|
Column("TABLE_ID", ULonglong(), NOT_NULL),
|
|
|
|
#define SYS_TABLESTATS_NAME 1
|
|
Column("NAME", Varchar(NAME_CHAR_LEN), NOT_NULL),
|
|
|
|
#define SYS_TABLESTATS_INIT 2
|
|
Column("STATS_INITIALIZED", SLong(1), NOT_NULL),
|
|
|
|
#define SYS_TABLESTATS_NROW 3
|
|
Column("NUM_ROWS", ULonglong(), NOT_NULL),
|
|
|
|
#define SYS_TABLESTATS_CLUST_SIZE 4
|
|
Column("CLUST_INDEX_SIZE", ULonglong(), NOT_NULL),
|
|
|
|
#define SYS_TABLESTATS_INDEX_SIZE 5
|
|
Column("OTHER_INDEX_SIZE", ULonglong(), NOT_NULL),
|
|
|
|
#define SYS_TABLESTATS_MODIFIED 6
|
|
Column("MODIFIED_COUNTER", ULonglong(), NOT_NULL),
|
|
|
|
#define SYS_TABLESTATS_AUTONINC 7
|
|
Column("AUTOINC", ULonglong(), NOT_NULL),
|
|
|
|
#define SYS_TABLESTATS_TABLE_REF_COUNT 8
|
|
Column("REF_COUNT", SLong(), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/** Populate information_schema.innodb_sys_tablestats table with a table,
|
|
and release exclusive dict_sys.latch.
|
|
@param[in] thd connection
|
|
@param[in,out] table InnoDB table metadata
|
|
@param[in,out] table_to_fill INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_dict_fill_sys_tablestats(THD* thd, dict_table_t *table,
|
|
TABLE* table_to_fill)
|
|
{
|
|
DBUG_ENTER("i_s_dict_fill_sys_tablestats");
|
|
|
|
Field **fields= table_to_fill->field;
|
|
|
|
{
|
|
table->stats_shared_lock();
|
|
auto _ = make_scope_exit([table]() {
|
|
table->stats_shared_unlock(); dict_sys.unlock(); });
|
|
|
|
OK(fields[SYS_TABLESTATS_ID]->store(longlong(table->id), TRUE));
|
|
|
|
OK(field_store_string(fields[SYS_TABLESTATS_NAME],
|
|
table->name.m_name));
|
|
OK(fields[SYS_TABLESTATS_INIT]->store(table->stat_initialized, true));
|
|
|
|
if (table->stat_initialized)
|
|
{
|
|
OK(fields[SYS_TABLESTATS_NROW]->store(table->stat_n_rows, true));
|
|
|
|
OK(fields[SYS_TABLESTATS_CLUST_SIZE]->
|
|
store(table->stat_clustered_index_size, true));
|
|
|
|
OK(fields[SYS_TABLESTATS_INDEX_SIZE]->
|
|
store(table->stat_sum_of_other_index_sizes, true));
|
|
|
|
OK(fields[SYS_TABLESTATS_MODIFIED]->
|
|
store(table->stat_modified_counter, true));
|
|
}
|
|
else
|
|
{
|
|
OK(fields[SYS_TABLESTATS_NROW]->store(0, true));
|
|
OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(0, true));
|
|
OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(0, true));
|
|
OK(fields[SYS_TABLESTATS_MODIFIED]->store(0, true));
|
|
}
|
|
|
|
OK(fields[SYS_TABLESTATS_AUTONINC]->store(table->autoinc, true));
|
|
|
|
OK(fields[SYS_TABLESTATS_TABLE_REF_COUNT]->
|
|
store(table->get_ref_count(), true));
|
|
}
|
|
|
|
OK(schema_table_store_record(thd, table_to_fill));
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Function to go through each record in SYS_TABLES table, and fill the
|
|
information_schema.innodb_sys_tablestats table with table statistics
|
|
related information
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_sys_tables_fill_table_stats(
|
|
/*============================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (not used) */
|
|
{
|
|
btr_pcur_t pcur;
|
|
const rec_t* rec;
|
|
mtr_t mtr;
|
|
int err = 0;
|
|
|
|
DBUG_ENTER("i_s_sys_tables_fill_table_stats");
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
/* deny access to user without PROCESS_ACL privilege */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
mtr.start();
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
|
|
rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_tables);
|
|
|
|
while (rec) {
|
|
const char* err_msg;
|
|
dict_table_t* table_rec = nullptr;
|
|
|
|
mtr.commit();
|
|
/* Fetch the dict_table_t structure corresponding to
|
|
this SYS_TABLES record */
|
|
err_msg = i_s_sys_tables_rec(pcur, nullptr, nullptr,
|
|
&table_rec);
|
|
|
|
if (UNIV_LIKELY(!err_msg)) {
|
|
err = i_s_dict_fill_sys_tablestats(thd, table_rec,
|
|
tables->table);
|
|
if (err) {
|
|
err = i_s_sys_error_handling(err, thd);
|
|
goto func_exit;
|
|
}
|
|
} else {
|
|
ut_ad(!table_rec);
|
|
dict_sys.unlock();
|
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
|
ER_CANT_FIND_SYSTEM_REC, "%s",
|
|
err_msg);
|
|
}
|
|
|
|
/* Get the next record */
|
|
mtr.start();
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
|
|
rec = dict_getnext_system(&pcur, &mtr);
|
|
}
|
|
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
func_exit:
|
|
ut_free(pcur.old_rec_buf);
|
|
DBUG_RETURN(err);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_tablestats
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
innodb_sys_tablestats_init(
|
|
/*=======================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("innodb_sys_tablestats_init");
|
|
|
|
schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::innodb_sys_tablestats_fields_info;
|
|
schema->fill_table = i_s_sys_tables_fill_table_stats;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_sys_tablestats =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_SYS_TABLESTATS",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB SYS_TABLESTATS",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
innodb_sys_tablestats_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
namespace Show {
|
|
/** SYS_INDEXES **************************************************/
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_INDEXES */
|
|
static ST_FIELD_INFO innodb_sysindex_fields_info[]=
|
|
{
|
|
#define SYS_INDEX_ID 0
|
|
Column("INDEX_ID", ULonglong(), NOT_NULL),
|
|
|
|
#define SYS_INDEX_NAME 1
|
|
Column("NAME", Varchar(NAME_CHAR_LEN), NOT_NULL),
|
|
|
|
#define SYS_INDEX_TABLE_ID 2
|
|
Column("TABLE_ID", ULonglong(), NOT_NULL),
|
|
|
|
#define SYS_INDEX_TYPE 3
|
|
Column("TYPE", SLong(), NOT_NULL),
|
|
|
|
#define SYS_INDEX_NUM_FIELDS 4
|
|
Column("N_FIELDS", SLong(), NOT_NULL),
|
|
|
|
#define SYS_INDEX_PAGE_NO 5
|
|
Column("PAGE_NO", SLong(), NULLABLE),
|
|
|
|
#define SYS_INDEX_SPACE 6
|
|
Column("SPACE", SLong(), NULLABLE),
|
|
|
|
#define SYS_INDEX_MERGE_THRESHOLD 7
|
|
Column("MERGE_THRESHOLD", SLong(), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/**********************************************************************//**
|
|
Function to populate the information_schema.innodb_sys_indexes table with
|
|
collected index information
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_dict_fill_sys_indexes(
|
|
/*======================*/
|
|
THD* thd, /*!< in: thread */
|
|
table_id_t table_id, /*!< in: table id */
|
|
ulint space_id, /*!< in: tablespace id */
|
|
dict_index_t* index, /*!< in: populated dict_index_t
|
|
struct with index info */
|
|
TABLE* table_to_fill) /*!< in/out: fill this table */
|
|
{
|
|
Field** fields;
|
|
|
|
DBUG_ENTER("i_s_dict_fill_sys_indexes");
|
|
|
|
fields = table_to_fill->field;
|
|
|
|
if (*index->name == *TEMP_INDEX_PREFIX_STR) {
|
|
/* Since TEMP_INDEX_PREFIX_STR is not valid UTF-8, we
|
|
need to convert it to something else. */
|
|
*const_cast<char*>(index->name()) = '?';
|
|
}
|
|
|
|
OK(fields[SYS_INDEX_NAME]->store(index->name,
|
|
uint(strlen(index->name)),
|
|
system_charset_info));
|
|
|
|
OK(fields[SYS_INDEX_ID]->store(longlong(index->id), true));
|
|
|
|
OK(fields[SYS_INDEX_TABLE_ID]->store(longlong(table_id), true));
|
|
|
|
OK(fields[SYS_INDEX_TYPE]->store(index->type, true));
|
|
|
|
OK(fields[SYS_INDEX_NUM_FIELDS]->store(index->n_fields));
|
|
|
|
/* FIL_NULL is ULINT32_UNDEFINED */
|
|
if (index->page == FIL_NULL) {
|
|
fields[SYS_INDEX_PAGE_NO]->set_null();
|
|
} else {
|
|
fields[SYS_INDEX_PAGE_NO]->set_notnull();
|
|
OK(fields[SYS_INDEX_PAGE_NO]->store(index->page, true));
|
|
}
|
|
|
|
if (space_id == FIL_NULL) {
|
|
fields[SYS_INDEX_SPACE]->set_null();
|
|
} else {
|
|
fields[SYS_INDEX_SPACE]->set_notnull();
|
|
OK(fields[SYS_INDEX_SPACE]->store(space_id, true));
|
|
}
|
|
|
|
OK(fields[SYS_INDEX_MERGE_THRESHOLD]->store(index->merge_threshold,
|
|
true));
|
|
|
|
OK(schema_table_store_record(thd, table_to_fill));
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
/*******************************************************************//**
|
|
Function to go through each record in SYS_INDEXES table, and fill the
|
|
information_schema.innodb_sys_indexes table with related index information
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_sys_indexes_fill_table(
|
|
/*=======================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (not used) */
|
|
{
|
|
btr_pcur_t pcur;
|
|
const rec_t* rec;
|
|
mem_heap_t* heap;
|
|
mtr_t mtr;
|
|
int err = 0;
|
|
|
|
DBUG_ENTER("i_s_sys_indexes_fill_table");
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
/* deny access to user without PROCESS_ACL privilege */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
heap = mem_heap_create(1000);
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
mtr_start(&mtr);
|
|
|
|
/* Start scan the SYS_INDEXES table */
|
|
rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_indexes);
|
|
|
|
/* Process each record in the table */
|
|
while (rec) {
|
|
const char* err_msg;
|
|
table_id_t table_id;
|
|
ulint space_id;
|
|
dict_index_t index_rec;
|
|
|
|
/* Populate a dict_index_t structure with information from
|
|
a SYS_INDEXES row */
|
|
err_msg = dict_process_sys_indexes_rec(heap, rec, &index_rec,
|
|
&table_id);
|
|
const byte* field = rec_get_nth_field_old(
|
|
rec, DICT_FLD__SYS_INDEXES__SPACE, &space_id);
|
|
space_id = space_id == 4 ? mach_read_from_4(field)
|
|
: ULINT_UNDEFINED;
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
|
|
if (!err_msg) {
|
|
err = i_s_dict_fill_sys_indexes(
|
|
thd, table_id, space_id,
|
|
&index_rec,
|
|
tables->table);
|
|
if (err) {
|
|
err = i_s_sys_error_handling(err, thd);
|
|
goto func_exit;
|
|
}
|
|
} else {
|
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
|
ER_CANT_FIND_SYSTEM_REC, "%s",
|
|
err_msg);
|
|
}
|
|
|
|
mem_heap_empty(heap);
|
|
|
|
/* Get the next record */
|
|
mtr.start();
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
rec = dict_getnext_system(&pcur, &mtr);
|
|
}
|
|
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
func_exit:
|
|
mem_heap_free(heap);
|
|
ut_free(pcur.old_rec_buf);
|
|
|
|
DBUG_RETURN(err);
|
|
}
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_indexes
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
innodb_sys_indexes_init(
|
|
/*====================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("innodb_sys_indexes_init");
|
|
|
|
schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::innodb_sysindex_fields_info;
|
|
schema->fill_table = i_s_sys_indexes_fill_table;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_sys_indexes =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_SYS_INDEXES",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB SYS_INDEXES",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
innodb_sys_indexes_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
namespace Show {
|
|
/** SYS_COLUMNS **************************************************/
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_COLUMNS */
|
|
static ST_FIELD_INFO innodb_sys_columns_fields_info[]=
|
|
{
|
|
#define SYS_COLUMN_TABLE_ID 0
|
|
Column("TABLE_ID", ULonglong(), NOT_NULL),
|
|
|
|
#define SYS_COLUMN_NAME 1
|
|
Column("NAME", Varchar(NAME_CHAR_LEN), NOT_NULL),
|
|
|
|
#define SYS_COLUMN_POSITION 2
|
|
Column("POS", ULonglong(), NOT_NULL),
|
|
|
|
#define SYS_COLUMN_MTYPE 3
|
|
Column("MTYPE", SLong(), NOT_NULL),
|
|
|
|
#define SYS_COLUMN__PRTYPE 4
|
|
Column("PRTYPE", SLong(), NOT_NULL),
|
|
|
|
#define SYS_COLUMN_COLUMN_LEN 5
|
|
Column("LEN", SLong(), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/**********************************************************************//**
|
|
Function to populate the information_schema.innodb_sys_columns with
|
|
related column information
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_dict_fill_sys_columns(
|
|
/*======================*/
|
|
THD* thd, /*!< in: thread */
|
|
table_id_t table_id, /*!< in: table ID */
|
|
const char* col_name, /*!< in: column name */
|
|
dict_col_t* column, /*!< in: dict_col_t struct holding
|
|
more column information */
|
|
ulint nth_v_col, /*!< in: virtual column, its
|
|
sequence number (nth virtual col) */
|
|
TABLE* table_to_fill) /*!< in/out: fill this table */
|
|
{
|
|
Field** fields;
|
|
|
|
DBUG_ENTER("i_s_dict_fill_sys_columns");
|
|
|
|
fields = table_to_fill->field;
|
|
|
|
OK(fields[SYS_COLUMN_TABLE_ID]->store((longlong) table_id, TRUE));
|
|
|
|
OK(field_store_string(fields[SYS_COLUMN_NAME], col_name));
|
|
|
|
if (column->is_virtual()) {
|
|
ulint pos = dict_create_v_col_pos(nth_v_col, column->ind);
|
|
OK(fields[SYS_COLUMN_POSITION]->store(pos, true));
|
|
} else {
|
|
OK(fields[SYS_COLUMN_POSITION]->store(column->ind, true));
|
|
}
|
|
|
|
OK(fields[SYS_COLUMN_MTYPE]->store(column->mtype));
|
|
|
|
OK(fields[SYS_COLUMN__PRTYPE]->store(column->prtype));
|
|
|
|
OK(fields[SYS_COLUMN_COLUMN_LEN]->store(column->len));
|
|
|
|
OK(schema_table_store_record(thd, table_to_fill));
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
/*******************************************************************//**
|
|
Function to fill information_schema.innodb_sys_columns with information
|
|
collected by scanning SYS_COLUMNS table.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_sys_columns_fill_table(
|
|
/*=======================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (not used) */
|
|
{
|
|
btr_pcur_t pcur;
|
|
const rec_t* rec;
|
|
const char* col_name;
|
|
mem_heap_t* heap;
|
|
mtr_t mtr;
|
|
int err = 0;
|
|
|
|
DBUG_ENTER("i_s_sys_columns_fill_table");
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
/* deny access to user without PROCESS_ACL privilege */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
heap = mem_heap_create(1000);
|
|
mtr.start();
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
|
|
rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_columns);
|
|
|
|
while (rec) {
|
|
const char* err_msg;
|
|
dict_col_t column_rec;
|
|
table_id_t table_id;
|
|
ulint nth_v_col;
|
|
|
|
/* populate a dict_col_t structure with information from
|
|
a SYS_COLUMNS row */
|
|
err_msg = dict_process_sys_columns_rec(heap, rec, &column_rec,
|
|
&table_id, &col_name,
|
|
&nth_v_col);
|
|
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
|
|
if (!err_msg) {
|
|
err = i_s_dict_fill_sys_columns(
|
|
thd, table_id, col_name,
|
|
&column_rec, nth_v_col,
|
|
tables->table);
|
|
if (err) {
|
|
err = i_s_sys_error_handling(err, thd);
|
|
goto func_exit;
|
|
}
|
|
} else {
|
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
|
ER_CANT_FIND_SYSTEM_REC, "%s",
|
|
err_msg);
|
|
}
|
|
|
|
mem_heap_empty(heap);
|
|
|
|
/* Get the next record */
|
|
mtr.start();
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
rec = dict_getnext_system(&pcur, &mtr);
|
|
}
|
|
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
func_exit:
|
|
mem_heap_free(heap);
|
|
ut_free(pcur.old_rec_buf);
|
|
|
|
DBUG_RETURN(err);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_columns
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
innodb_sys_columns_init(
|
|
/*====================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("innodb_sys_columns_init");
|
|
|
|
schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::innodb_sys_columns_fields_info;
|
|
schema->fill_table = i_s_sys_columns_fill_table;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_sys_columns =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_SYS_COLUMNS",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB SYS_COLUMNS",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
innodb_sys_columns_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
namespace Show {
|
|
/** SYS_VIRTUAL **************************************************/
|
|
/** Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_VIRTUAL */
|
|
static ST_FIELD_INFO innodb_sys_virtual_fields_info[]=
|
|
{
|
|
#define SYS_VIRTUAL_TABLE_ID 0
|
|
Column("TABLE_ID", ULonglong(), NOT_NULL),
|
|
|
|
#define SYS_VIRTUAL_POS 1
|
|
Column("POS", ULong(), NOT_NULL),
|
|
|
|
#define SYS_VIRTUAL_BASE_POS 2
|
|
Column("BASE_POS", ULong(), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/** Function to populate the information_schema.innodb_sys_virtual with
|
|
related information
|
|
param[in] thd thread
|
|
param[in] table_id table ID
|
|
param[in] pos virtual column position
|
|
param[in] base_pos base column position
|
|
param[in,out] table_to_fill fill this table
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_dict_fill_sys_virtual(
|
|
THD* thd,
|
|
table_id_t table_id,
|
|
ulint pos,
|
|
ulint base_pos,
|
|
TABLE* table_to_fill)
|
|
{
|
|
Field** fields;
|
|
|
|
DBUG_ENTER("i_s_dict_fill_sys_virtual");
|
|
|
|
fields = table_to_fill->field;
|
|
|
|
OK(fields[SYS_VIRTUAL_TABLE_ID]->store(table_id, true));
|
|
|
|
OK(fields[SYS_VIRTUAL_POS]->store(pos, true));
|
|
|
|
OK(fields[SYS_VIRTUAL_BASE_POS]->store(base_pos, true));
|
|
|
|
OK(schema_table_store_record(thd, table_to_fill));
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/** Function to fill information_schema.innodb_sys_virtual with information
|
|
collected by scanning SYS_VIRTUAL table.
|
|
param[in] thd thread
|
|
param[in,out] tables tables to fill
|
|
param[in] item condition (not used)
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_sys_virtual_fill_table(
|
|
THD* thd,
|
|
TABLE_LIST* tables,
|
|
Item* )
|
|
{
|
|
btr_pcur_t pcur;
|
|
const rec_t* rec;
|
|
ulint pos;
|
|
ulint base_pos;
|
|
mtr_t mtr;
|
|
int err = 0;
|
|
|
|
DBUG_ENTER("i_s_sys_virtual_fill_table");
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
/* deny access to user without PROCESS_ACL privilege */
|
|
if (check_global_access(thd, PROCESS_ACL) || !dict_sys.sys_virtual) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
mtr.start();
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
|
|
rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_virtual);
|
|
|
|
while (rec) {
|
|
const char* err_msg;
|
|
table_id_t table_id;
|
|
|
|
/* populate a dict_col_t structure with information from
|
|
a SYS_VIRTUAL row */
|
|
err_msg = dict_process_sys_virtual_rec(rec,
|
|
&table_id, &pos,
|
|
&base_pos);
|
|
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
|
|
if (!err_msg) {
|
|
err = i_s_dict_fill_sys_virtual(
|
|
thd, table_id, pos, base_pos,
|
|
tables->table);
|
|
if (err) {
|
|
err = i_s_sys_error_handling(err, thd);
|
|
goto func_exit;
|
|
}
|
|
} else {
|
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
|
ER_CANT_FIND_SYSTEM_REC, "%s",
|
|
err_msg);
|
|
}
|
|
|
|
/* Get the next record */
|
|
mtr.start();
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
rec = dict_getnext_system(&pcur, &mtr);
|
|
}
|
|
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
|
|
DBUG_RETURN(0);
|
|
func_exit:
|
|
ut_free(pcur.old_rec_buf);
|
|
DBUG_RETURN(err);
|
|
}
|
|
|
|
/** Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_virtual
|
|
param[in,out] p table schema object
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
innodb_sys_virtual_init(
|
|
void* p)
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("innodb_sys_virtual_init");
|
|
|
|
schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::innodb_sys_virtual_fields_info;
|
|
schema->fill_table = i_s_sys_virtual_fill_table;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_sys_virtual =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_SYS_VIRTUAL",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB SYS_VIRTUAL",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
innodb_sys_virtual_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
|
|
namespace Show {
|
|
/** SYS_FIELDS ***************************************************/
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FIELDS */
|
|
static ST_FIELD_INFO innodb_sys_fields_fields_info[]=
|
|
{
|
|
#define SYS_FIELD_INDEX_ID 0
|
|
Column("INDEX_ID", ULonglong(), NOT_NULL),
|
|
|
|
#define SYS_FIELD_NAME 1
|
|
Column("NAME", Varchar(NAME_CHAR_LEN), NOT_NULL),
|
|
|
|
#define SYS_FIELD_POS 2
|
|
Column("POS", ULong(), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/**********************************************************************//**
|
|
Function to fill information_schema.innodb_sys_fields with information
|
|
collected by scanning SYS_FIELDS table.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_dict_fill_sys_fields(
|
|
/*=====================*/
|
|
THD* thd, /*!< in: thread */
|
|
index_id_t index_id, /*!< in: index id for the field */
|
|
dict_field_t* field, /*!< in: table */
|
|
ulint pos, /*!< in: Field position */
|
|
TABLE* table_to_fill) /*!< in/out: fill this table */
|
|
{
|
|
Field** fields;
|
|
|
|
DBUG_ENTER("i_s_dict_fill_sys_fields");
|
|
|
|
fields = table_to_fill->field;
|
|
|
|
OK(fields[SYS_FIELD_INDEX_ID]->store(index_id, true));
|
|
|
|
OK(field_store_string(fields[SYS_FIELD_NAME], field->name));
|
|
|
|
OK(fields[SYS_FIELD_POS]->store(pos, true));
|
|
|
|
OK(schema_table_store_record(thd, table_to_fill));
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
/*******************************************************************//**
|
|
Function to go through each record in SYS_FIELDS table, and fill the
|
|
information_schema.innodb_sys_fields table with related index field
|
|
information
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_sys_fields_fill_table(
|
|
/*======================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (not used) */
|
|
{
|
|
btr_pcur_t pcur;
|
|
const rec_t* rec;
|
|
mem_heap_t* heap;
|
|
index_id_t last_id;
|
|
mtr_t mtr;
|
|
int err = 0;
|
|
|
|
DBUG_ENTER("i_s_sys_fields_fill_table");
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
/* deny access to user without PROCESS_ACL privilege */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
heap = mem_heap_create(1000);
|
|
mtr.start();
|
|
|
|
/* will save last index id so that we know whether we move to
|
|
the next index. This is used to calculate prefix length */
|
|
last_id = 0;
|
|
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_fields);
|
|
|
|
while (rec) {
|
|
ulint pos;
|
|
const char* err_msg;
|
|
index_id_t index_id;
|
|
dict_field_t field_rec;
|
|
|
|
/* Populate a dict_field_t structure with information from
|
|
a SYS_FIELDS row */
|
|
err_msg = dict_process_sys_fields_rec(heap, rec, &field_rec,
|
|
&pos, &index_id, last_id);
|
|
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
|
|
if (!err_msg) {
|
|
err = i_s_dict_fill_sys_fields(
|
|
thd, index_id, &field_rec,
|
|
pos, tables->table);
|
|
if (err) {
|
|
err = i_s_sys_error_handling(err, thd);
|
|
goto func_exit;
|
|
}
|
|
last_id = index_id;
|
|
} else {
|
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
|
ER_CANT_FIND_SYSTEM_REC, "%s",
|
|
err_msg);
|
|
}
|
|
|
|
mem_heap_empty(heap);
|
|
|
|
/* Get the next record */
|
|
mtr.start();
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
rec = dict_getnext_system(&pcur, &mtr);
|
|
}
|
|
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
func_exit:
|
|
mem_heap_free(heap);
|
|
ut_free(pcur.old_rec_buf);
|
|
|
|
DBUG_RETURN(err);
|
|
}
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_fields
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
innodb_sys_fields_init(
|
|
/*===================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("innodb_sys_field_init");
|
|
|
|
schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::innodb_sys_fields_fields_info;
|
|
schema->fill_table = i_s_sys_fields_fill_table;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_sys_fields =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_SYS_FIELDS",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB SYS_FIELDS",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
innodb_sys_fields_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
namespace Show {
|
|
/** SYS_FOREIGN ********************************************/
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FOREIGN */
|
|
static ST_FIELD_INFO innodb_sys_foreign_fields_info[]=
|
|
{
|
|
#define SYS_FOREIGN_ID 0
|
|
Column("ID", Varchar(NAME_LEN + 1), NOT_NULL),
|
|
|
|
#define SYS_FOREIGN_FOR_NAME 1
|
|
Column("FOR_NAME", Varchar(NAME_LEN + 1), NOT_NULL),
|
|
|
|
#define SYS_FOREIGN_REF_NAME 2
|
|
Column("REF_NAME", Varchar(NAME_LEN + 1), NOT_NULL),
|
|
|
|
#define SYS_FOREIGN_NUM_COL 3
|
|
Column("N_COLS", ULong(), NOT_NULL),
|
|
|
|
#define SYS_FOREIGN_TYPE 4
|
|
Column("TYPE", ULong(), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/**********************************************************************//**
|
|
Function to fill information_schema.innodb_sys_foreign with information
|
|
collected by scanning SYS_FOREIGN table.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_dict_fill_sys_foreign(
|
|
/*======================*/
|
|
THD* thd, /*!< in: thread */
|
|
dict_foreign_t* foreign, /*!< in: table */
|
|
TABLE* table_to_fill) /*!< in/out: fill this table */
|
|
{
|
|
Field** fields;
|
|
|
|
DBUG_ENTER("i_s_dict_fill_sys_foreign");
|
|
|
|
fields = table_to_fill->field;
|
|
|
|
OK(field_store_string(fields[SYS_FOREIGN_ID], foreign->id));
|
|
|
|
OK(field_store_string(fields[SYS_FOREIGN_FOR_NAME],
|
|
foreign->foreign_table_name));
|
|
|
|
OK(field_store_string(fields[SYS_FOREIGN_REF_NAME],
|
|
foreign->referenced_table_name));
|
|
|
|
OK(fields[SYS_FOREIGN_NUM_COL]->store(foreign->n_fields));
|
|
|
|
OK(fields[SYS_FOREIGN_TYPE]->store(foreign->type));
|
|
|
|
OK(schema_table_store_record(thd, table_to_fill));
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Function to populate INFORMATION_SCHEMA.innodb_sys_foreign table. Loop
|
|
through each record in SYS_FOREIGN, and extract the foreign key
|
|
information.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_sys_foreign_fill_table(
|
|
/*=======================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (not used) */
|
|
{
|
|
btr_pcur_t pcur;
|
|
const rec_t* rec;
|
|
mem_heap_t* heap;
|
|
mtr_t mtr;
|
|
int err = 0;
|
|
|
|
DBUG_ENTER("i_s_sys_foreign_fill_table");
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
/* deny access to user without PROCESS_ACL privilege */
|
|
if (check_global_access(thd, PROCESS_ACL) || !dict_sys.sys_foreign) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
heap = mem_heap_create(1000);
|
|
mtr.start();
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
|
|
rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_foreign);
|
|
|
|
while (rec) {
|
|
const char* err_msg;
|
|
dict_foreign_t foreign_rec;
|
|
|
|
/* Populate a dict_foreign_t structure with information from
|
|
a SYS_FOREIGN row */
|
|
err_msg = dict_process_sys_foreign_rec(heap, rec, &foreign_rec);
|
|
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
|
|
if (!err_msg) {
|
|
err = i_s_dict_fill_sys_foreign(
|
|
thd, &foreign_rec, tables->table);
|
|
if (err) {
|
|
err = i_s_sys_error_handling(err, thd);
|
|
goto func_exit;
|
|
}
|
|
} else {
|
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
|
ER_CANT_FIND_SYSTEM_REC, "%s",
|
|
err_msg);
|
|
}
|
|
|
|
mem_heap_empty(heap);
|
|
|
|
/* Get the next record */
|
|
mtr.start();
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
rec = dict_getnext_system(&pcur, &mtr);
|
|
}
|
|
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
func_exit:
|
|
mem_heap_free(heap);
|
|
ut_free(pcur.old_rec_buf);
|
|
|
|
DBUG_RETURN(err);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
innodb_sys_foreign_init(
|
|
/*====================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("innodb_sys_foreign_init");
|
|
|
|
schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::innodb_sys_foreign_fields_info;
|
|
schema->fill_table = i_s_sys_foreign_fill_table;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_sys_foreign =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_SYS_FOREIGN",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB SYS_FOREIGN",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
innodb_sys_foreign_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
namespace Show {
|
|
/** SYS_FOREIGN_COLS ********************************************/
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS */
|
|
static ST_FIELD_INFO innodb_sys_foreign_cols_fields_info[]=
|
|
{
|
|
#define SYS_FOREIGN_COL_ID 0
|
|
Column("ID", Varchar(NAME_LEN + 1), NOT_NULL),
|
|
|
|
#define SYS_FOREIGN_COL_FOR_NAME 1
|
|
Column("FOR_COL_NAME", Varchar(NAME_CHAR_LEN), NOT_NULL),
|
|
|
|
#define SYS_FOREIGN_COL_REF_NAME 2
|
|
Column("REF_COL_NAME", Varchar(NAME_CHAR_LEN), NOT_NULL),
|
|
|
|
#define SYS_FOREIGN_COL_POS 3
|
|
Column("POS", ULong(), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/**********************************************************************//**
|
|
Function to fill information_schema.innodb_sys_foreign_cols with information
|
|
collected by scanning SYS_FOREIGN_COLS table.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_dict_fill_sys_foreign_cols(
|
|
/*==========================*/
|
|
THD* thd, /*!< in: thread */
|
|
const char* name, /*!< in: foreign key constraint name */
|
|
const char* for_col_name, /*!< in: referencing column name*/
|
|
const char* ref_col_name, /*!< in: referenced column
|
|
name */
|
|
ulint pos, /*!< in: column position */
|
|
TABLE* table_to_fill) /*!< in/out: fill this table */
|
|
{
|
|
Field** fields;
|
|
|
|
DBUG_ENTER("i_s_dict_fill_sys_foreign_cols");
|
|
|
|
fields = table_to_fill->field;
|
|
|
|
OK(field_store_string(fields[SYS_FOREIGN_COL_ID], name));
|
|
|
|
OK(field_store_string(fields[SYS_FOREIGN_COL_FOR_NAME], for_col_name));
|
|
|
|
OK(field_store_string(fields[SYS_FOREIGN_COL_REF_NAME], ref_col_name));
|
|
|
|
OK(fields[SYS_FOREIGN_COL_POS]->store(pos, true));
|
|
|
|
OK(schema_table_store_record(thd, table_to_fill));
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
/*******************************************************************//**
|
|
Function to populate INFORMATION_SCHEMA.innodb_sys_foreign_cols table. Loop
|
|
through each record in SYS_FOREIGN_COLS, and extract the foreign key column
|
|
information and fill the INFORMATION_SCHEMA.innodb_sys_foreign_cols table.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_sys_foreign_cols_fill_table(
|
|
/*============================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (not used) */
|
|
{
|
|
btr_pcur_t pcur;
|
|
const rec_t* rec;
|
|
mem_heap_t* heap;
|
|
mtr_t mtr;
|
|
int err = 0;
|
|
|
|
DBUG_ENTER("i_s_sys_foreign_cols_fill_table");
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
/* deny access to user without PROCESS_ACL privilege */
|
|
if (check_global_access(thd, PROCESS_ACL)
|
|
|| !dict_sys.sys_foreign_cols) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
heap = mem_heap_create(1000);
|
|
mtr.start();
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
|
|
rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_foreign_cols);
|
|
|
|
while (rec) {
|
|
const char* err_msg;
|
|
const char* name;
|
|
const char* for_col_name;
|
|
const char* ref_col_name;
|
|
ulint pos;
|
|
|
|
/* Extract necessary information from a SYS_FOREIGN_COLS row */
|
|
err_msg = dict_process_sys_foreign_col_rec(
|
|
heap, rec, &name, &for_col_name, &ref_col_name, &pos);
|
|
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
|
|
if (!err_msg) {
|
|
err = i_s_dict_fill_sys_foreign_cols(
|
|
thd, name, for_col_name,
|
|
ref_col_name, pos, tables->table);
|
|
if (err) {
|
|
err = i_s_sys_error_handling(err, thd);
|
|
goto func_exit;
|
|
}
|
|
} else {
|
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
|
ER_CANT_FIND_SYSTEM_REC, "%s",
|
|
err_msg);
|
|
}
|
|
|
|
mem_heap_empty(heap);
|
|
|
|
/* Get the next record */
|
|
mtr.start();
|
|
dict_sys.lock(SRW_LOCK_CALL);
|
|
rec = dict_getnext_system(&pcur, &mtr);
|
|
}
|
|
|
|
mtr.commit();
|
|
dict_sys.unlock();
|
|
func_exit:
|
|
mem_heap_free(heap);
|
|
ut_free(pcur.old_rec_buf);
|
|
|
|
DBUG_RETURN(err);
|
|
}
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign_cols
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
innodb_sys_foreign_cols_init(
|
|
/*========================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("innodb_sys_foreign_cols_init");
|
|
|
|
schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::innodb_sys_foreign_cols_fields_info;
|
|
schema->fill_table = i_s_sys_foreign_cols_fill_table;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_sys_foreign_cols =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_SYS_FOREIGN_COLS",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB SYS_FOREIGN_COLS",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
innodb_sys_foreign_cols_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
namespace Show {
|
|
/** SYS_TABLESPACES ********************************************/
|
|
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES */
|
|
static ST_FIELD_INFO innodb_sys_tablespaces_fields_info[]=
|
|
{
|
|
#define SYS_TABLESPACES_SPACE 0
|
|
Column("SPACE", ULong(), NOT_NULL),
|
|
|
|
#define SYS_TABLESPACES_NAME 1
|
|
Column("NAME", Varchar(MAX_FULL_NAME_LEN + 1), NOT_NULL),
|
|
|
|
#define SYS_TABLESPACES_FLAGS 2
|
|
Column("FLAG", ULong(), NOT_NULL),
|
|
|
|
#define SYS_TABLESPACES_ROW_FORMAT 3
|
|
Column("ROW_FORMAT", Varchar(22), NULLABLE),
|
|
|
|
#define SYS_TABLESPACES_PAGE_SIZE 4
|
|
Column("PAGE_SIZE", ULong(), NOT_NULL),
|
|
|
|
#define SYS_TABLESPACES_FILENAME 5
|
|
Column("FILENAME", Varchar(FN_REFLEN), NOT_NULL),
|
|
|
|
#define SYS_TABLESPACES_FS_BLOCK_SIZE 6
|
|
Column("FS_BLOCK_SIZE", ULong(),NOT_NULL),
|
|
|
|
#define SYS_TABLESPACES_FILE_SIZE 7
|
|
Column("FILE_SIZE", ULonglong(), NOT_NULL),
|
|
|
|
#define SYS_TABLESPACES_ALLOC_SIZE 8
|
|
Column("ALLOCATED_SIZE", ULonglong(), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
extern size_t os_file_get_fs_block_size(const char *path);
|
|
|
|
/** Produce one row of INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES.
|
|
@param thd connection
|
|
@param s tablespace
|
|
@param t output table
|
|
@return 0 on success */
|
|
static int i_s_sys_tablespaces_fill(THD *thd, const fil_space_t &s, TABLE *t)
|
|
{
|
|
DBUG_ENTER("i_s_sys_tablespaces_fill");
|
|
const char *row_format;
|
|
|
|
if (s.full_crc32() || is_system_tablespace(s.id))
|
|
row_format= nullptr;
|
|
else if (FSP_FLAGS_GET_ZIP_SSIZE(s.flags))
|
|
row_format= "Compressed";
|
|
else if (FSP_FLAGS_HAS_ATOMIC_BLOBS(s.flags))
|
|
row_format= "Dynamic";
|
|
else
|
|
row_format= "Compact or Redundant";
|
|
|
|
Field **fields= t->field;
|
|
|
|
OK(fields[SYS_TABLESPACES_SPACE]->store(s.id, true));
|
|
{
|
|
Field *f= fields[SYS_TABLESPACES_NAME];
|
|
const auto name= s.name();
|
|
if (name.data())
|
|
{
|
|
OK(f->store(name.data(), name.size(), system_charset_info));
|
|
f->set_notnull();
|
|
}
|
|
else if (srv_is_undo_tablespace(s.id))
|
|
{
|
|
char name[15];
|
|
snprintf(name, sizeof name, "innodb_undo%03u",
|
|
(s.id - srv_undo_space_id_start + 1));
|
|
OK(f->store(name, strlen(name), system_charset_info));
|
|
} else f->set_notnull();
|
|
}
|
|
|
|
fields[SYS_TABLESPACES_NAME]->set_null();
|
|
OK(fields[SYS_TABLESPACES_FLAGS]->store(s.flags, true));
|
|
OK(field_store_string(fields[SYS_TABLESPACES_ROW_FORMAT], row_format));
|
|
const char *filepath= s.chain.start->name;
|
|
OK(field_store_string(fields[SYS_TABLESPACES_FILENAME], filepath));
|
|
|
|
OK(fields[SYS_TABLESPACES_PAGE_SIZE]->store(s.physical_size(), true));
|
|
size_t fs_block_size;
|
|
os_file_size_t file= os_file_get_size(filepath);
|
|
if (file.m_total_size == os_offset_t(~0))
|
|
{
|
|
file.m_total_size= 0;
|
|
file.m_alloc_size= 0;
|
|
fs_block_size= 0;
|
|
}
|
|
else
|
|
fs_block_size= os_file_get_fs_block_size(filepath);
|
|
|
|
OK(fields[SYS_TABLESPACES_FS_BLOCK_SIZE]->store(fs_block_size, true));
|
|
OK(fields[SYS_TABLESPACES_FILE_SIZE]->store(file.m_total_size, true));
|
|
OK(fields[SYS_TABLESPACES_ALLOC_SIZE]->store(file.m_alloc_size, true));
|
|
|
|
OK(schema_table_store_record(thd, t));
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/** Populate INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES.
|
|
@param thd connection
|
|
@param tables table to fill
|
|
@return 0 on success */
|
|
static int i_s_sys_tablespaces_fill_table(THD *thd, TABLE_LIST *tables, Item*)
|
|
{
|
|
DBUG_ENTER("i_s_sys_tablespaces_fill_table");
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
if (check_global_access(thd, PROCESS_ACL))
|
|
DBUG_RETURN(0);
|
|
|
|
int err= 0;
|
|
|
|
mysql_mutex_lock(&fil_system.mutex);
|
|
fil_system.freeze_space_list++;
|
|
|
|
for (fil_space_t &space : fil_system.space_list)
|
|
{
|
|
if (!space.is_temporary() && !space.is_being_imported() &&
|
|
!space.is_stopping() &&
|
|
space.chain.start)
|
|
{
|
|
space.reacquire();
|
|
mysql_mutex_unlock(&fil_system.mutex);
|
|
space.s_lock();
|
|
err= i_s_sys_tablespaces_fill(thd, space, tables->table);
|
|
space.s_unlock();
|
|
mysql_mutex_lock(&fil_system.mutex);
|
|
space.release();
|
|
if (err)
|
|
break;
|
|
}
|
|
}
|
|
|
|
fil_system.freeze_space_list--;
|
|
mysql_mutex_unlock(&fil_system.mutex);
|
|
if (err == DB_SUCCESS)
|
|
err= i_s_sys_tablespaces_fill(thd, *fil_system.temp_space, tables->table);
|
|
else
|
|
err = i_s_sys_error_handling(err, thd);
|
|
DBUG_RETURN(err);
|
|
}
|
|
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
innodb_sys_tablespaces_init(
|
|
/*========================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("innodb_sys_tablespaces_init");
|
|
|
|
schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::innodb_sys_tablespaces_fields_info;
|
|
schema->fill_table = i_s_sys_tablespaces_fill_table;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_sys_tablespaces =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_SYS_TABLESPACES",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
plugin_author,
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB tablespaces",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_GPL,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
innodb_sys_tablespaces_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|
|
|
|
namespace Show {
|
|
/** TABLESPACES_ENCRYPTION ********************************************/
|
|
/* Fields of the table INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION */
|
|
static ST_FIELD_INFO innodb_tablespaces_encryption_fields_info[]=
|
|
{
|
|
#define TABLESPACES_ENCRYPTION_SPACE 0
|
|
Column("SPACE", ULong(), NOT_NULL),
|
|
|
|
#define TABLESPACES_ENCRYPTION_NAME 1
|
|
Column("NAME", Varchar(MAX_FULL_NAME_LEN + 1), NULLABLE),
|
|
|
|
#define TABLESPACES_ENCRYPTION_ENCRYPTION_SCHEME 2
|
|
Column("ENCRYPTION_SCHEME", ULong(), NOT_NULL),
|
|
|
|
#define TABLESPACES_ENCRYPTION_KEYSERVER_REQUESTS 3
|
|
Column("KEYSERVER_REQUESTS", ULong(), NOT_NULL),
|
|
|
|
#define TABLESPACES_ENCRYPTION_MIN_KEY_VERSION 4
|
|
Column("MIN_KEY_VERSION", ULong(), NOT_NULL),
|
|
|
|
#define TABLESPACES_ENCRYPTION_CURRENT_KEY_VERSION 5
|
|
Column("CURRENT_KEY_VERSION", ULong(), NOT_NULL),
|
|
|
|
#define TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER 6
|
|
Column("KEY_ROTATION_PAGE_NUMBER", ULonglong(), NULLABLE),
|
|
|
|
#define TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER 7
|
|
Column("KEY_ROTATION_MAX_PAGE_NUMBER", ULonglong(), NULLABLE),
|
|
|
|
#define TABLESPACES_ENCRYPTION_CURRENT_KEY_ID 8
|
|
Column("CURRENT_KEY_ID", ULong(), NOT_NULL),
|
|
|
|
#define TABLESPACES_ENCRYPTION_ROTATING_OR_FLUSHING 9
|
|
Column("ROTATING_OR_FLUSHING", SLong(1), NOT_NULL),
|
|
|
|
CEnd()
|
|
};
|
|
} // namespace Show
|
|
|
|
/**********************************************************************//**
|
|
Function to fill INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION.
|
|
@param[in] thd thread handle
|
|
@param[in] space Tablespace
|
|
@param[in] table_to_fill I_S table to fill
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_dict_fill_tablespaces_encryption(
|
|
THD* thd,
|
|
fil_space_t* space,
|
|
TABLE* table_to_fill)
|
|
{
|
|
Field** fields;
|
|
struct fil_space_crypt_status_t status;
|
|
DBUG_ENTER("i_s_dict_fill_tablespaces_encryption");
|
|
|
|
fields = table_to_fill->field;
|
|
|
|
fil_space_crypt_get_status(space, &status);
|
|
|
|
/* If tablespace id does not match, we did not find
|
|
encryption information for this tablespace. */
|
|
if (!space->crypt_data || space->id != status.space) {
|
|
goto skip;
|
|
}
|
|
|
|
OK(fields[TABLESPACES_ENCRYPTION_SPACE]->store(space->id, true));
|
|
|
|
{
|
|
const auto name = space->name();
|
|
if (name.data()) {
|
|
OK(fields[TABLESPACES_ENCRYPTION_NAME]->store(
|
|
name.data(), name.size(),
|
|
system_charset_info));
|
|
fields[TABLESPACES_ENCRYPTION_NAME]->set_notnull();
|
|
} else if (srv_is_undo_tablespace(space->id)) {
|
|
char undo_name[sizeof "innodb_undo000"];
|
|
snprintf(undo_name, sizeof undo_name,
|
|
"innodb_undo%03" PRIu32, space->id);
|
|
OK(fields[TABLESPACES_ENCRYPTION_NAME]->store(
|
|
undo_name, strlen(undo_name),
|
|
system_charset_info));
|
|
fields[TABLESPACES_ENCRYPTION_NAME]->set_notnull();
|
|
} else {
|
|
fields[TABLESPACES_ENCRYPTION_NAME]->set_null();
|
|
}
|
|
}
|
|
|
|
OK(fields[TABLESPACES_ENCRYPTION_ENCRYPTION_SCHEME]->store(
|
|
status.scheme, true));
|
|
OK(fields[TABLESPACES_ENCRYPTION_KEYSERVER_REQUESTS]->store(
|
|
status.keyserver_requests, true));
|
|
OK(fields[TABLESPACES_ENCRYPTION_MIN_KEY_VERSION]->store(
|
|
status.min_key_version, true));
|
|
OK(fields[TABLESPACES_ENCRYPTION_CURRENT_KEY_VERSION]->store(
|
|
status.current_key_version, true));
|
|
OK(fields[TABLESPACES_ENCRYPTION_CURRENT_KEY_ID]->store(
|
|
status.key_id, true));
|
|
OK(fields[TABLESPACES_ENCRYPTION_ROTATING_OR_FLUSHING]->store(
|
|
status.rotating || status.flushing, true));
|
|
|
|
if (status.rotating) {
|
|
fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]->set_notnull();
|
|
OK(fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]->store(
|
|
status.rotate_next_page_number, true));
|
|
fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER]->set_notnull();
|
|
OK(fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER]->store(
|
|
status.rotate_max_page_number, true));
|
|
} else {
|
|
fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]
|
|
->set_null();
|
|
fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER]
|
|
->set_null();
|
|
}
|
|
|
|
OK(schema_table_store_record(thd, table_to_fill));
|
|
|
|
skip:
|
|
DBUG_RETURN(0);
|
|
}
|
|
/*******************************************************************//**
|
|
Function to populate INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION table.
|
|
Loop through each record in TABLESPACES_ENCRYPTION, and extract the column
|
|
information and fill the INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION table.
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
i_s_tablespaces_encryption_fill_table(
|
|
/*===========================*/
|
|
THD* thd, /*!< in: thread */
|
|
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
|
Item* ) /*!< in: condition (not used) */
|
|
{
|
|
DBUG_ENTER("i_s_tablespaces_encryption_fill_table");
|
|
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
|
|
|
|
/* deny access to user without PROCESS_ACL privilege */
|
|
if (check_global_access(thd, PROCESS_ACL)) {
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int err = 0;
|
|
mysql_mutex_lock(&fil_system.mutex);
|
|
fil_system.freeze_space_list++;
|
|
|
|
for (fil_space_t& space : fil_system.space_list) {
|
|
if (!space.is_temporary() && !space.is_being_imported()
|
|
&& !space.is_stopping()) {
|
|
space.reacquire();
|
|
mysql_mutex_unlock(&fil_system.mutex);
|
|
space.s_lock();
|
|
err = i_s_dict_fill_tablespaces_encryption(
|
|
thd, &space, tables->table);
|
|
space.s_unlock();
|
|
mysql_mutex_lock(&fil_system.mutex);
|
|
space.release();
|
|
if (err) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
fil_system.freeze_space_list--;
|
|
mysql_mutex_unlock(&fil_system.mutex);
|
|
DBUG_RETURN(err);
|
|
}
|
|
/*******************************************************************//**
|
|
Bind the dynamic table INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION
|
|
@return 0 on success */
|
|
static
|
|
int
|
|
innodb_tablespaces_encryption_init(
|
|
/*========================*/
|
|
void* p) /*!< in/out: table schema object */
|
|
{
|
|
ST_SCHEMA_TABLE* schema;
|
|
|
|
DBUG_ENTER("innodb_tablespaces_encryption_init");
|
|
|
|
schema = (ST_SCHEMA_TABLE*) p;
|
|
|
|
schema->fields_info = Show::innodb_tablespaces_encryption_fields_info;
|
|
schema->fill_table = i_s_tablespaces_encryption_fill_table;
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
struct st_maria_plugin i_s_innodb_tablespaces_encryption =
|
|
{
|
|
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
|
/* int */
|
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
|
|
|
/* pointer to type-specific plugin descriptor */
|
|
/* void* */
|
|
&i_s_info,
|
|
|
|
/* plugin name */
|
|
/* const char* */
|
|
"INNODB_TABLESPACES_ENCRYPTION",
|
|
|
|
/* plugin author (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"Google Inc",
|
|
|
|
/* general descriptive text (for SHOW PLUGINS) */
|
|
/* const char* */
|
|
"InnoDB TABLESPACES_ENCRYPTION",
|
|
|
|
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
|
/* int */
|
|
PLUGIN_LICENSE_BSD,
|
|
|
|
/* the function to invoke when plugin is loaded */
|
|
/* int (*)(void*); */
|
|
innodb_tablespaces_encryption_init,
|
|
|
|
/* the function to invoke when plugin is unloaded */
|
|
/* int (*)(void*); */
|
|
i_s_common_deinit,
|
|
|
|
i_s_version, nullptr, nullptr, PACKAGE_VERSION,
|
|
MariaDB_PLUGIN_MATURITY_STABLE
|
|
};
|