summaryrefslogtreecommitdiffstats
path: root/storage/innobase/handler/i_s.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:24:36 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:24:36 +0000
commit06eaf7232e9a920468c0f8d74dcf2fe8b555501c (patch)
treee2c7b5777f728320e5b5542b6213fd3591ba51e2 /storage/innobase/handler/i_s.cc
parentInitial commit. (diff)
downloadmariadb-06eaf7232e9a920468c0f8d74dcf2fe8b555501c.tar.xz
mariadb-06eaf7232e9a920468c0f8d74dcf2fe8b555501c.zip
Adding upstream version 1:10.11.6.upstream/1%10.11.6
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'storage/innobase/handler/i_s.cc')
-rw-r--r--storage/innobase/handler/i_s.cc6506
1 files changed, 6506 insertions, 0 deletions
diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
new file mode 100644
index 00000000..b00308d7
--- /dev/null
+++ b/storage/innobase/handler/i_s.cc
@@ -0,0 +1,6506 @@
+/*****************************************************************************
+
+Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2022, MariaDB Corporation.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file 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 "ibuf0ibuf.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)
+
+/** Change buffer B-tree page */
+#define I_S_PAGE_TYPE_IBUF (FIL_PAGE_TYPE_LAST + 2)
+
+#define I_S_PAGE_TYPE_LAST I_S_PAGE_TYPE_IBUF
+
+#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},
+ {"IBUF_INDEX", I_S_PAGE_TYPE_IBUF},
+ {"PAGE COMPRESSED", FIL_PAGE_PAGE_COMPRESSED},
+ {"PAGE COMPRESSED AND ENCRYPTED", FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED},
+};
+
+/** 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 == 1U << 29, "comp.");
+ static_assert(buf_page_t::READ_FIX == 4U << 29, "comp.");
+ static_assert(buf_page_t::WRITE_FIX == 5U << 29, "comp.");
+
+ unsigned io_fix = page_info->state >> 29;
+ if (io_fix < 4) {
+ io_fix = 1;
+ } else if (io_fix > 5) {
+ io_fix = 3;
+ } else {
+ io_fix -= 2;
+ }
+
+ 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 or I_S_PAGE_TYPE_IBUF for
+ change buffer index pages */
+ if (page_type == FIL_PAGE_RTREE) {
+ page_info->page_type = I_S_PAGE_TYPE_RTREE;
+ } else if (page_info->index_id
+ == static_cast<index_id_t>(DICT_IBUF_ID_MIN
+ + IBUF_SPACE_ID)) {
+ page_info->page_type = I_S_PAGE_TYPE_IBUF;
+ } 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 == 1U << 29, "compatibility");
+ static_assert(buf_page_t::READ_FIX == 4U << 29, "compatibility");
+ static_assert(buf_page_t::WRITE_FIX == 5U << 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 == 1U << 29, "comp.");
+ static_assert(buf_page_t::READ_FIX == 4U << 29, "comp.");
+ static_assert(buf_page_t::WRITE_FIX == 5U << 29, "comp.");
+
+ unsigned io_fix = page_info->state >> 29;
+ if (io_fix < 4) {
+ io_fix = 1;
+ } else if (io_fix > 5) {
+ io_fix = 3;
+ } else {
+ io_fix -= 2;
+ }
+
+ 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);
+}
+
+/** 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;
+
+ 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) {
+ i_s_dict_fill_sys_tables(thd, table_rec,
+ tables->table);
+ } 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();
+
+ DBUG_RETURN(0);
+}
+
+/*******************************************************************//**
+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_mutex_lock();
+ auto _ = make_scope_exit([table]() {
+ table->stats_mutex_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;
+
+ 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)) {
+ i_s_dict_fill_sys_tablestats(thd, table_rec,
+ tables->table);
+ } 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();
+
+ DBUG_RETURN(0);
+}
+
+/*******************************************************************//**
+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;
+
+ 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) {
+ if (int err = i_s_dict_fill_sys_indexes(
+ thd, table_id, space_id, &index_rec,
+ tables->table)) {
+ mem_heap_free(heap);
+ DBUG_RETURN(err);
+ }
+ } 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();
+ mem_heap_free(heap);
+
+ DBUG_RETURN(0);
+}
+/*******************************************************************//**
+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;
+
+ 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) {
+ i_s_dict_fill_sys_columns(thd, table_id, col_name,
+ &column_rec, nth_v_col,
+ tables->table);
+ } 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();
+ mem_heap_free(heap);
+
+ DBUG_RETURN(0);
+}
+
+/*******************************************************************//**
+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;
+
+ 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) {
+ i_s_dict_fill_sys_virtual(thd, table_id, pos, base_pos,
+ tables->table);
+ } 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);
+}
+
+/** 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;
+
+ 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) {
+ i_s_dict_fill_sys_fields(thd, index_id, &field_rec,
+ pos, tables->table);
+ 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();
+ mem_heap_free(heap);
+
+ DBUG_RETURN(0);
+}
+/*******************************************************************//**
+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;
+
+ 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) {
+ i_s_dict_fill_sys_foreign(thd, &foreign_rec,
+ tables->table);
+ } 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();
+ mem_heap_free(heap);
+
+ DBUG_RETURN(0);
+}
+
+/*******************************************************************//**
+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;
+
+ 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) {
+ i_s_dict_fill_sys_foreign_cols(
+ thd, name, for_col_name, ref_col_name, pos,
+ tables->table);
+ } 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();
+ mem_heap_free(heap);
+
+ DBUG_RETURN(0);
+}
+/*******************************************************************//**
+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.purpose == FIL_TYPE_TABLESPACE && !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);
+ 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.purpose == FIL_TYPE_TABLESPACE
+ && !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
+};