summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorJimmy Yang <jimmy.yang@oracle.com>2010-05-25 18:44:33 -0700
committerJimmy Yang <jimmy.yang@oracle.com>2010-05-25 18:44:33 -0700
commit00dfb12b9221ec1b2b84d9ddd1309e0b440fc889 (patch)
tree54d2fd9cdef475dd2487f9d00495e5580c93e63d /storage
parent7d50be10d2d5f9cff913b386ac0f1473971b993e (diff)
downloadmariadb-git-00dfb12b9221ec1b2b84d9ddd1309e0b440fc889.tar.gz
Check in the support for Information Schema System Table Views. Users
can now view the content of InnoDB System Tables through following information schema tables: information_schema.INNODB_SYS_TABLES information_schema.INNODB_SYS_INDEXES information_schema.INNODB_SYS_COUMNS information_schema.INNODB_SYS_FIELDS information_schema.INNODB_SYS_FOREIGN information_schema.INNODB_SYS_FOREIGN_COLS information_schema.INNODB_SYS_TABLESTATS rb://330 Approved by Marko
Diffstat (limited to 'storage')
-rw-r--r--storage/innobase/dict/dict0load.c1249
-rw-r--r--storage/innobase/dict/dict0mem.c35
-rw-r--r--storage/innobase/handler/ha_innodb.cc10
-rw-r--r--storage/innobase/handler/i_s.cc1667
-rw-r--r--storage/innobase/handler/i_s.h7
-rw-r--r--storage/innobase/include/dict0dict.ic2
-rw-r--r--storage/innobase/include/dict0load.h208
-rw-r--r--storage/innobase/include/dict0mem.h30
-rw-r--r--storage/innobase/include/dict0mem.ic78
-rw-r--r--storage/innobase/row/row0mysql.c4
10 files changed, 2978 insertions, 312 deletions
diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c
index 377818308c5..0aa53b9dd22 100644
--- a/storage/innobase/dict/dict0load.c
+++ b/storage/innobase/dict/dict0load.c
@@ -41,6 +41,16 @@ Created 4/24/1996 Heikki Tuuri
#include "srv0start.h"
#include "srv0srv.h"
+
+/** Following are six InnoDB system tables */
+static const char* SYSTEM_TABLE_NAME[] = {
+ "SYS_TABLES",
+ "SYS_INDEXES",
+ "SYS_COLUMNS",
+ "SYS_FIELDS",
+ "SYS_FOREIGN",
+ "SYS_FOREIGN_COLS"
+};
/****************************************************************//**
Compare the name of an index column.
@return TRUE if the i'th column of index is 'name'. */
@@ -151,13 +161,10 @@ void
dict_print(void)
/*============*/
{
- dict_table_t* sys_tables;
- dict_index_t* sys_index;
dict_table_t* table;
btr_pcur_t pcur;
const rec_t* rec;
- const byte* field;
- ulint len;
+ mem_heap_t* heap;
mtr_t mtr;
/* Enlarge the fatal semaphore wait timeout during the InnoDB table
@@ -167,75 +174,396 @@ dict_print(void)
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
mutex_exit(&kernel_mutex);
+ heap = mem_heap_create(1000);
mutex_enter(&(dict_sys->mutex));
-
mtr_start(&mtr);
- sys_tables = dict_table_get_low("SYS_TABLES");
- sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
+ rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
- btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
- TRUE, &mtr);
-loop:
- btr_pcur_move_to_next_user_rec(&pcur, &mtr);
+ while (rec) {
+ const char* err_msg;
- rec = btr_pcur_get_rec(&pcur);
+ err_msg = dict_process_sys_tables_rec(
+ heap, rec, &table, DICT_TABLE_LOAD_FROM_CACHE
+ | DICT_TABLE_UPDATE_STATS);
- if (!btr_pcur_is_on_user_rec(&pcur)) {
- /* end of index */
-
- btr_pcur_close(&pcur);
mtr_commit(&mtr);
- mutex_exit(&(dict_sys->mutex));
+ if (!err_msg) {
+ dict_table_print_low(table);
+ } else {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: %s\n", err_msg);
+ }
+
+ mem_heap_empty(heap);
- /* Restore the fatal semaphore wait timeout */
+ mtr_start(&mtr);
+ rec = dict_getnext_system(&pcur, &mtr);
+ }
- mutex_enter(&kernel_mutex);
- srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
- mutex_exit(&kernel_mutex);
+ mtr_commit(&mtr);
+ mutex_exit(&(dict_sys->mutex));
+ mem_heap_free(heap);
- return;
+ /* Restore the fatal semaphore wait timeout */
+ mutex_enter(&kernel_mutex);
+ srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
+ mutex_exit(&kernel_mutex);
+}
+
+
+/********************************************************************//**
+This function gets the next system table record as it scans the table.
+@return the next record if found, NULL if end of scan */
+static
+const rec_t*
+dict_getnext_system_low(
+/*====================*/
+ btr_pcur_t* pcur, /*!< in/out: persistent cursor to the
+ record*/
+ mtr_t* mtr) /*!< in: the mini-transaction */
+{
+ rec_t* rec = NULL;
+
+ while (!rec || rec_get_deleted_flag(rec, 0)) {
+ btr_pcur_move_to_next_user_rec(pcur, mtr);
+
+ rec = btr_pcur_get_rec(pcur);
+
+ if (!btr_pcur_is_on_user_rec(pcur)) {
+ /* end of index */
+ btr_pcur_close(pcur);
+
+ return(NULL);
+ }
}
- field = rec_get_nth_field_old(rec, 0, &len);
+ /* Get a record, let's save the position */
+ btr_pcur_store_position(pcur, mtr);
- if (!rec_get_deleted_flag(rec, 0)) {
+ return(rec);
+}
- /* We found one */
+/********************************************************************//**
+This function opens a system table, and return the first record.
+@return first record of the system table */
+UNIV_INTERN
+const rec_t*
+dict_startscan_system(
+/*==================*/
+ btr_pcur_t* pcur, /*!< out: persistent cursor to
+ the record */
+ mtr_t* mtr, /*!< in: the mini-transaction */
+ dict_system_id_t system_id) /*!< in: which system table to open */
+{
+ dict_table_t* system_table;
+ dict_index_t* clust_index;
+ const rec_t* rec;
- char* table_name = mem_strdupl((char*) field, len);
+ ut_a(system_id < SYS_NUM_SYSTEM_TABLES);
- btr_pcur_store_position(&pcur, &mtr);
+ system_table = dict_table_get_low(SYSTEM_TABLE_NAME[system_id]);
- mtr_commit(&mtr);
+ clust_index = UT_LIST_GET_FIRST(system_table->indexes);
- table = dict_table_get_low(table_name);
- mem_free(table_name);
+ btr_pcur_open_at_index_side(TRUE, clust_index, BTR_SEARCH_LEAF, pcur,
+ TRUE, mtr);
- if (table == NULL) {
- fputs("InnoDB: Failed to load table ", stderr);
- ut_print_namel(stderr, NULL, TRUE, (char*) field, len);
- putc('\n', stderr);
- } else {
- /* The table definition was corrupt if there
- is no index */
+ rec = dict_getnext_system_low(pcur, mtr);
- if (dict_table_get_first_index(table)) {
- dict_update_statistics_low(table, TRUE);
- }
+ return(rec);
+}
- dict_table_print_low(table);
+/********************************************************************//**
+This function gets the next system table record as it scans the table.
+@return the next record if found, NULL if end of scan */
+UNIV_INTERN
+const rec_t*
+dict_getnext_system(
+/*================*/
+ btr_pcur_t* pcur, /*!< in/out: persistent cursor
+ to the record */
+ mtr_t* mtr) /*!< in: the mini-transaction */
+{
+ const rec_t* rec;
+
+ /* Restore the position */
+ btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
+
+ /* Get the next record */
+ rec = dict_getnext_system_low(pcur, mtr);
+
+ return(rec);
+}
+/********************************************************************//**
+This function processes one SYS_TABLES record and populate the dict_table_t
+struct for the table. Extracted out of dict_print() to be used by
+both monitor table output and information schema innodb_sys_tables output.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_tables_rec(
+/*========================*/
+ mem_heap_t* heap, /*!< in/out: temporary memory heap */
+ const rec_t* rec, /*!< in: SYS_TABLES record */
+ dict_table_t** table, /*!< out: dict_table_t to fill */
+ dict_table_info_t status) /*!< in: status bit controls
+ options such as whether we shall
+ look for dict_table_t from cache
+ first */
+{
+ ulint len;
+ const byte* field;
+ const char* err_msg = NULL;
+ char* table_name;
+
+ field = rec_get_nth_field_old(rec, 0, &len);
+
+ ut_a(!rec_get_deleted_flag(rec, 0));
+
+ /* Get the table name */
+ table_name = mem_heap_strdupl(heap, field, len);
+
+ /* If DICT_TABLE_LOAD_FROM_CACHE is set, first check
+ whether there is cached dict_table_t struct first */
+ if (status & DICT_TABLE_LOAD_FROM_CACHE) {
+ *table = dict_table_get_low(table_name);
+
+ if (!(*table)) {
+ err_msg = "Table not found in cache";
}
+ } else {
+ err_msg = dict_load_table_low(table_name, rec, table);
+ }
- mtr_start(&mtr);
+ if (err_msg) {
+ return(err_msg);
+ }
- btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
+ if ((status & DICT_TABLE_UPDATE_STATS)
+ && dict_table_get_first_index(*table)) {
+
+ /* Update statistics if DICT_TABLE_UPDATE_STATS
+ is set */
+ dict_update_statistics_low(*table, TRUE);
}
- goto loop;
+ return(NULL);
+}
+
+/********************************************************************//**
+This function parses a SYS_INDEXES record and populate a dict_index_t
+structure with the information from the record. For detail information
+about SYS_INDEXES fields, please refer to dict_boot() function.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_indexes_rec(
+/*=========================*/
+ mem_heap_t* heap, /*!< in/out: heap memory */
+ const rec_t* rec, /*!< in: current SYS_INDEXES rec */
+ dict_index_t* index, /*!< out: index to be filled */
+ dulint* table_id) /*!< out: index table id */
+{
+ const char* err_msg;
+ byte* buf;
+
+ buf = mem_heap_alloc(heap, 8);
+
+ /* Parse the record, and get "dict_index_t" struct filled */
+ err_msg = dict_load_index_low(buf, NULL,
+ heap, rec, FALSE, &index);
+
+ *table_id = mach_read_from_8(buf);
+
+ return(err_msg);
+}
+/********************************************************************//**
+This function parses a SYS_COLUMNS record and populate a dict_column_t
+structure with the information from the record.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_columns_rec(
+/*=========================*/
+ mem_heap_t* heap, /*!< in/out: heap memory */
+ const rec_t* rec, /*!< in: current SYS_COLUMNS rec */
+ dict_col_t* column, /*!< out: dict_col_t to be filled */
+ dulint* table_id, /*!< out: table id */
+ const char** col_name) /*!< out: column name */
+{
+ const char* err_msg;
+
+ /* Parse the record, and get "dict_col_t" struct filled */
+ err_msg = dict_load_column_low(NULL, heap, column,
+ table_id, col_name, rec);
+
+ return(err_msg);
+}
+/********************************************************************//**
+This function parses a SYS_FIELDS record and populates a dict_field_t
+structure with the information from the record.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_fields_rec(
+/*========================*/
+ mem_heap_t* heap, /*!< in/out: heap memory */
+ const rec_t* rec, /*!< in: current SYS_FIELDS rec */
+ dict_field_t* sys_field, /*!< out: dict_field_t to be
+ filled */
+ ulint* pos, /*!< out: Field position */
+ dulint* index_id, /*!< out: current index id */
+ dulint last_id) /*!< in: previous index id */
+{
+ byte* buf;
+ byte* last_index_id;
+ const char* err_msg;
+
+ buf = mem_heap_alloc(heap, 8);
+
+ last_index_id = mem_heap_alloc(heap, 8);
+ mach_write_to_8(last_index_id, last_id);
+
+ err_msg = dict_load_field_low(buf, NULL, sys_field,
+ pos, last_index_id, heap, rec);
+
+ *index_id = mach_read_from_8(buf);
+
+ return(err_msg);
+
+}
+/********************************************************************//**
+This function parses a SYS_FOREIGN record and populate a dict_foreign_t
+structure with the information from the record. For detail information
+about SYS_FOREIGN fields, please refer to dict_load_foreign() function
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_foreign_rec(
+/*=========================*/
+ mem_heap_t* heap, /*!< in/out: heap memory */
+ const rec_t* rec, /*!< in: current SYS_FOREIGN rec */
+ dict_foreign_t* foreign) /*!< out: dict_foreign_t struct
+ to be filled */
+{
+ ulint len;
+ const byte* field;
+ ulint n_fields_and_type;
+
+ if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
+ return("delete-marked record in SYS_FOREIGN");
+ }
+
+ if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 6)) {
+ return("wrong number of columns in SYS_FOREIGN record");
+ }
+
+ field = rec_get_nth_field_old(rec, 0/*ID*/, &len);
+ if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+err_len:
+ return("incorrect column length in SYS_FOREIGN");
+ }
+ foreign->id = mem_heap_strdupl(heap, (const char*) field, len);
+
+ rec_get_nth_field_offs_old(rec, 1/*DB_TRX_ID*/, &len);
+ if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+ rec_get_nth_field_offs_old(rec, 2/*DB_ROLL_PTR*/, &len);
+ if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+
+ field = rec_get_nth_field_old(rec, 3/*FOR_NAME*/, &len);
+ if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+ foreign->foreign_table_name = mem_heap_strdupl(
+ heap, (const char*) field, len);
+
+ field = rec_get_nth_field_old(rec, 4/*REF_NAME*/, &len);
+ if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+ foreign->referenced_table_name = mem_heap_strdupl(
+ heap, (const char*) field, len);
+
+ field = rec_get_nth_field_old(rec, 5/*N_COLS*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
+ }
+ n_fields_and_type = mach_read_from_4(field);
+
+ foreign->type = (unsigned int) (n_fields_and_type >> 24);
+ foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
+
+ return(NULL);
}
+/********************************************************************//**
+This function parses a SYS_FOREIGN_COLS record and extract necessary
+information from the record and return to caller.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_foreign_col_rec(
+/*=============================*/
+ mem_heap_t* heap, /*!< in/out: heap memory */
+ const rec_t* rec, /*!< in: current SYS_FOREIGN_COLS rec */
+ const char** name, /*!< out: foreign key constraint name */
+ const char** for_col_name, /*!< out: referencing column name */
+ const char** ref_col_name, /*!< out: referenced column name
+ in referenced table */
+ ulint* pos) /*!< out: column position */
+{
+ ulint len;
+ const byte* field;
+
+ if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
+ return("delete-marked record in SYS_FOREIGN_COLS");
+ }
+
+ if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 6)) {
+ return("wrong number of columns in SYS_FOREIGN_COLS record");
+ }
+
+ field = rec_get_nth_field_old(rec, 0/*ID*/, &len);
+ if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+err_len:
+ return("incorrect column length in SYS_FOREIGN_COLS");
+ }
+ *name = mem_heap_strdupl(heap, (char*) field, len);
+
+ field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
+ }
+ *pos = mach_read_from_4(field);
+
+ rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
+ if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+ rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
+ if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+
+ field = rec_get_nth_field_old(rec, 4/*FOR_COL_NAME*/, &len);
+ if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+ *for_col_name = mem_heap_strdupl(heap, (char*) field, len);
+
+ field = rec_get_nth_field_old(rec, 5/*REF_COL_NAME*/, &len);
+ if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+ *ref_col_name = mem_heap_strdupl(heap, (char*) field, len);
+ return(NULL);
+}
/********************************************************************//**
Determine the flags of a table described in SYS_TABLES.
@return compressed page size in kilobytes; or 0 if the tablespace is
@@ -441,13 +769,149 @@ loop:
}
/********************************************************************//**
+Loads a table column definition from a SYS_COLUMNS record to
+dict_table_t.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_load_column_low(
+/*=================*/
+ dict_table_t* table, /*!< in/out: table, could be NULL
+ if we just polulate a dict_column_t
+ struct with information from
+ a SYS_COLUMNS record */
+ mem_heap_t* heap, /*!< in/out: memory heap
+ for temporary storage */
+ dict_col_t* column, /*!< out: dict_column_t to fill */
+ dulint* table_id, /*!< out: table id */
+ const char** col_name, /*!< out: column name */
+ const rec_t* rec) /*!< in: SYS_COLUMNS record */
+{
+ char* name;
+ const byte* field;
+ ulint len;
+ ulint mtype;
+ ulint prtype;
+ ulint col_len;
+ ulint pos;
+
+ if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
+ return("delete-marked record in SYS_COLUMNS");
+ }
+
+ if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) {
+ return("wrong number of columns in SYS_COLUMNS record");
+ }
+
+ field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len);
+ if (UNIV_UNLIKELY(len != 8)) {
+err_len:
+ return("incorrect column length in SYS_COLUMNS");
+ }
+
+ if (table_id) {
+ *table_id = mach_read_from_8(field);
+ } else if (UNIV_UNLIKELY(ut_dulint_cmp(table->id,
+ mach_read_from_8(field)))) {
+ return("SYS_COLUMNS.TABLE_ID mismatch");
+ }
+
+ field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+
+ goto err_len;
+ }
+
+ if (!table) {
+ pos = mach_read_from_4(field);
+ } else if (UNIV_UNLIKELY(table->n_def != mach_read_from_4(field))) {
+ return("SYS_COLUMNS.POS mismatch");
+ }
+
+ rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
+ if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+ rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
+ if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+
+ field = rec_get_nth_field_old(rec, 4/*NAME*/, &len);
+ if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+
+ name = mem_heap_strdupl(heap, (const char*) field, len);
+
+ if (col_name) {
+ *col_name = name;
+ }
+
+ field = rec_get_nth_field_old(rec, 5/*MTYPE*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
+ }
+
+ mtype = mach_read_from_4(field);
+
+ field = rec_get_nth_field_old(rec, 6/*PRTYPE*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
+ }
+ prtype = mach_read_from_4(field);
+
+ if (dtype_get_charset_coll(prtype) == 0
+ && dtype_is_string_type(mtype)) {
+ /* The table was created with < 4.1.2. */
+
+ if (dtype_is_binary_string_type(mtype, prtype)) {
+ /* Use the binary collation for
+ string columns of binary type. */
+
+ prtype = dtype_form_prtype(
+ prtype,
+ DATA_MYSQL_BINARY_CHARSET_COLL);
+ } else {
+ /* Use the default charset for
+ other than binary columns. */
+
+ prtype = dtype_form_prtype(
+ prtype,
+ data_mysql_default_charset_coll);
+ }
+ }
+
+ field = rec_get_nth_field_old(rec, 7/*LEN*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
+ }
+ col_len = mach_read_from_4(field);
+ field = rec_get_nth_field_old(rec, 8/*PREC*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
+ }
+
+ if (!column) {
+ dict_mem_table_add_col(table, heap, name, mtype,
+ prtype, col_len);
+ } else {
+ dict_mem_fill_column_struct(column, pos, mtype,
+ prtype, col_len);
+ }
+
+ return(NULL);
+}
+
+/********************************************************************//**
Loads definitions for table columns. */
static
void
dict_load_columns(
/*==============*/
- dict_table_t* table, /*!< in: table */
- mem_heap_t* heap) /*!< in: memory heap for temporary storage */
+ dict_table_t* table, /*!< in/out: table */
+ mem_heap_t* heap) /*!< in/out: memory heap
+ for temporary storage */
{
dict_table_t* sys_columns;
dict_index_t* sys_index;
@@ -455,13 +919,7 @@ dict_load_columns(
dtuple_t* tuple;
dfield_t* dfield;
const rec_t* rec;
- const byte* field;
- ulint len;
byte* buf;
- char* name;
- ulint mtype;
- ulint prtype;
- ulint col_len;
ulint i;
mtr_t mtr;
@@ -473,6 +931,9 @@ dict_load_columns(
sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
ut_a(!dict_table_is_comp(sys_columns));
+ ut_a(name_of_col_is(sys_columns, sys_index, 4, "NAME"));
+ ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC"));
+
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
@@ -485,74 +946,156 @@ dict_load_columns(
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
+ const char* err_msg;
rec = btr_pcur_get_rec(&pcur);
ut_a(btr_pcur_is_on_user_rec(&pcur));
- ut_a(!rec_get_deleted_flag(rec, 0));
+ err_msg = dict_load_column_low(table, heap, NULL, NULL,
+ NULL, rec);
- field = rec_get_nth_field_old(rec, 0, &len);
- ut_ad(len == 8);
- ut_a(ut_dulint_cmp(table->id, mach_read_from_8(field)) == 0);
+ if (err_msg) {
+ fprintf(stderr, "InnoDB: %s\n", err_msg);
+ ut_error;
+ }
- field = rec_get_nth_field_old(rec, 1, &len);
- ut_ad(len == 4);
- ut_a(i == mach_read_from_4(field));
+ btr_pcur_move_to_next_user_rec(&pcur, &mtr);
+ }
- ut_a(name_of_col_is(sys_columns, sys_index, 4, "NAME"));
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+}
- field = rec_get_nth_field_old(rec, 4, &len);
- name = mem_heap_strdupl(heap, (char*) field, len);
+/** Error message for a delete-marked record in dict_load_field_low() */
+static const char* dict_load_field_del = "delete-marked record in SYS_FIELDS";
- field = rec_get_nth_field_old(rec, 5, &len);
- mtype = mach_read_from_4(field);
+/********************************************************************//**
+Loads an index field definition from a SYS_FIELDS record to
+dict_index_t.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_load_field_low(
+/*================*/
+ byte* index_id, /*!< in/out: index id (8 bytes)
+ an "in" value if index != NULL
+ and "out" if index == NULL */
+ dict_index_t* index, /*!< in/out: index, could be NULL
+ if we just populate a dict_field_t
+ struct with information from
+ a SYS_FIELDSS record */
+ dict_field_t* sys_field, /*!< out: dict_field_t to be
+ filled */
+ ulint* pos, /*!< out: Field position */
+ byte* last_index_id, /*!< in: last index id */
+ mem_heap_t* heap, /*!< in/out: memory heap
+ for temporary storage */
+ const rec_t* rec) /*!< in: SYS_FIELDS record */
+{
+ const byte* field;
+ ulint len;
+ ulint pos_and_prefix_len;
+ ulint prefix_len;
+ ibool first_field;
+ ulint position;
- field = rec_get_nth_field_old(rec, 6, &len);
- prtype = mach_read_from_4(field);
+ /* Either index or sys_field is supplied, not both */
+ ut_a((!index) || (!sys_field));
- if (dtype_get_charset_coll(prtype) == 0
- && dtype_is_string_type(mtype)) {
- /* The table was created with < 4.1.2. */
+ if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
+ return(dict_load_field_del);
+ }
- if (dtype_is_binary_string_type(mtype, prtype)) {
- /* Use the binary collation for
- string columns of binary type. */
+ if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 5)) {
+ return("wrong number of columns in SYS_FIELDS record");
+ }
- prtype = dtype_form_prtype(
- prtype,
- DATA_MYSQL_BINARY_CHARSET_COLL);
- } else {
- /* Use the default charset for
- other than binary columns. */
+ field = rec_get_nth_field_old(rec, 0/*INDEX_ID*/, &len);
+ if (UNIV_UNLIKELY(len != 8)) {
+err_len:
+ return("incorrect column length in SYS_FIELDS");
+ }
- prtype = dtype_form_prtype(
- prtype,
- data_mysql_default_charset_coll);
- }
+ if (!index) {
+ ut_a(last_index_id);
+ memcpy(index_id, (const char*)field, 8);
+ first_field = memcmp(index_id, last_index_id, 8);
+ } else {
+ first_field = (index->n_def == 0);
+ if (memcmp(field, index_id, 8)) {
+ return("SYS_FIELDS.INDEX_ID mismatch");
}
+ }
- field = rec_get_nth_field_old(rec, 7, &len);
- col_len = mach_read_from_4(field);
+ field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
+ }
- ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC"));
+ rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
+ if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+ rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
+ if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
+ goto err_len;
+ }
- dict_mem_table_add_col(table, heap, name,
- mtype, prtype, col_len);
- btr_pcur_move_to_next_user_rec(&pcur, &mtr);
+ /* The next field stores the field position in the index and a
+ possible column prefix length if the index field does not
+ contain the whole column. The storage format is like this: if
+ there is at least one prefix field in the index, then the HIGH
+ 2 bytes contain the field number (index->n_def) and the low 2
+ bytes the prefix length for the field. Otherwise the field
+ number (index->n_def) is contained in the 2 LOW bytes. */
+
+ pos_and_prefix_len = mach_read_from_4(field);
+
+ if (index && UNIV_UNLIKELY
+ ((pos_and_prefix_len & 0xFFFFUL) != index->n_def
+ && (pos_and_prefix_len >> 16 & 0xFFFF) != index->n_def)) {
+ return("SYS_FIELDS.POS mismatch");
}
- btr_pcur_close(&pcur);
- mtr_commit(&mtr);
+ if (first_field || pos_and_prefix_len > 0xFFFFUL) {
+ prefix_len = pos_and_prefix_len & 0xFFFFUL;
+ position = (pos_and_prefix_len & 0xFFFF0000UL) >> 16;
+ } else {
+ prefix_len = 0;
+ position = pos_and_prefix_len & 0xFFFFUL;
+ }
+
+ field = rec_get_nth_field_old(rec, 4, &len);
+ if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+
+ if (index) {
+ dict_mem_index_add_field(
+ index, mem_heap_strdupl(heap, (const char*) field, len),
+ prefix_len);
+ } else {
+ ut_a(sys_field);
+ ut_a(pos);
+
+ sys_field->name = mem_heap_strdupl(
+ heap, (const char*) field, len);
+ sys_field->prefix_len = prefix_len;
+ *pos = position;
+ }
+
+ return(NULL);
}
/********************************************************************//**
-Loads definitions for index fields. */
+Loads definitions for index fields.
+@return DB_SUCCESS if ok, DB_CORRUPTION if corruption */
static
-void
+ulint
dict_load_fields(
/*=============*/
- dict_index_t* index, /*!< in: index whose fields to load */
+ dict_index_t* index, /*!< in/out: index whose fields to load */
mem_heap_t* heap) /*!< in: memory heap for temporary storage */
{
dict_table_t* sys_fields;
@@ -560,14 +1103,11 @@ dict_load_fields(
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
- ulint pos_and_prefix_len;
- ulint prefix_len;
const rec_t* rec;
- const byte* field;
- ulint len;
byte* buf;
ulint i;
mtr_t mtr;
+ ulint error;
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -576,6 +1116,7 @@ dict_load_fields(
sys_fields = dict_table_get_low("SYS_FIELDS");
sys_index = UT_LIST_GET_FIRST(sys_fields->indexes);
ut_a(!dict_table_is_comp(sys_fields));
+ ut_a(name_of_col_is(sys_fields, sys_index, 4, "COL_NAME"));
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
@@ -589,62 +1130,153 @@ dict_load_fields(
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
for (i = 0; i < index->n_fields; i++) {
+ const char* err_msg;
rec = btr_pcur_get_rec(&pcur);
ut_a(btr_pcur_is_on_user_rec(&pcur));
- /* There could be delete marked records in SYS_FIELDS
- because SYS_FIELDS.INDEX_ID can be updated
- by ALTER TABLE ADD INDEX. */
+ err_msg = dict_load_field_low(buf, index, NULL, NULL, NULL,
+ heap, rec);
- if (rec_get_deleted_flag(rec, 0)) {
+ if (err_msg == dict_load_field_del) {
+ /* There could be delete marked records in
+ SYS_FIELDS because SYS_FIELDS.INDEX_ID can be
+ updated by ALTER TABLE ADD INDEX. */
goto next_rec;
+ } else if (err_msg) {
+ fprintf(stderr, "InnoDB: %s\n", err_msg);
+ error = DB_CORRUPTION;
+ goto func_exit;
}
+next_rec:
+ btr_pcur_move_to_next_user_rec(&pcur, &mtr);
+ }
- field = rec_get_nth_field_old(rec, 0, &len);
- ut_ad(len == 8);
+ error = DB_SUCCESS;
+func_exit:
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+ return(error);
+}
- field = rec_get_nth_field_old(rec, 1, &len);
- ut_a(len == 4);
+/** Error message for a delete-marked record in dict_load_index_low() */
+static const char* dict_load_index_del = "delete-marked record in SYS_INDEXES";
+/** Error message for table->id mismatch in dict_load_index_low() */
+static const char* dict_load_index_id_err = "SYS_INDEXES.TABLE_ID mismatch";
- /* The next field stores the field position in the index
- and a possible column prefix length if the index field
- does not contain the whole column. The storage format is
- like this: if there is at least one prefix field in the index,
- then the HIGH 2 bytes contain the field number (== i) and the
- low 2 bytes the prefix length for the field. Otherwise the
- field number (== i) is contained in the 2 LOW bytes. */
+/********************************************************************//**
+Loads an index definition from a SYS_INDEXES record to dict_index_t.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_load_index_low(
+/*================*/
+ byte* table_id, /*!< in/out: table id (8 bytes),
+ an "in" value if cached=TRUE
+ and "out" when cached=FALSE */
+ const char* table_name, /*!< in: table name */
+ mem_heap_t* heap, /*!< in/out: temporary memory heap */
+ const rec_t* rec, /*!< in: SYS_INDEXES record */
+ ibool cached, /*!< in: TRUE = add to cache,
+ FALSE = do not */
+ dict_index_t** index) /*!< out,own: index, or NULL */
+{
+ const byte* field;
+ ulint len;
+ ulint name_len;
+ char* name_buf;
+ dulint id;
+ ulint n_fields;
+ ulint type;
+ ulint space;
+
+ if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
+ return(dict_load_index_del);
+ }
- pos_and_prefix_len = mach_read_from_4(field);
+ if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) {
+ return("wrong number of columns in SYS_INDEXES record");
+ }
- ut_a((pos_and_prefix_len & 0xFFFFUL) == i
- || (pos_and_prefix_len & 0xFFFF0000UL) == (i << 16));
+ field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len);
+ if (UNIV_UNLIKELY(len != 8)) {
+err_len:
+ return("incorrect column length in SYS_INDEXES");
+ }
- if ((i == 0 && pos_and_prefix_len > 0)
- || (pos_and_prefix_len & 0xFFFF0000UL) > 0) {
+ if (!cached) {
+ /* We are reading a SYS_INDEXES record. Copy the table_id */
+ memcpy(table_id, (const char*)field, 8);
+ } else if (memcmp(field, table_id, 8)) {
+ /* Caller supplied table_id, verify it is the same
+ id as on the index record */
+ return(dict_load_index_id_err);
+ }
- prefix_len = pos_and_prefix_len & 0xFFFFUL;
- } else {
- prefix_len = 0;
- }
+ field = rec_get_nth_field_old(rec, 1/*ID*/, &len);
+ if (UNIV_UNLIKELY(len != 8)) {
+ goto err_len;
+ }
- ut_a(name_of_col_is(sys_fields, sys_index, 4, "COL_NAME"));
+ id = mach_read_from_8(field);
- field = rec_get_nth_field_old(rec, 4, &len);
+ rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
+ if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+ rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
+ if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
+ goto err_len;
+ }
- dict_mem_index_add_field(index,
- mem_heap_strdupl(heap,
- (char*) field, len),
- prefix_len);
+ field = rec_get_nth_field_old(rec, 4/*NAME*/, &name_len);
+ if (UNIV_UNLIKELY(name_len == UNIV_SQL_NULL)) {
+ goto err_len;
+ }
-next_rec:
- btr_pcur_move_to_next_user_rec(&pcur, &mtr);
+ name_buf = mem_heap_strdupl(heap, (const char*) field,
+ name_len);
+
+ field = rec_get_nth_field_old(rec, 5/*N_FIELDS*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
}
+ n_fields = mach_read_from_4(field);
- btr_pcur_close(&pcur);
- mtr_commit(&mtr);
+ field = rec_get_nth_field_old(rec, 6/*TYPE*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
+ }
+ type = mach_read_from_4(field);
+
+ field = rec_get_nth_field_old(rec, 7/*SPACE*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
+ }
+ space = mach_read_from_4(field);
+
+ field = rec_get_nth_field_old(rec, 8/*PAGE_NO*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
+ }
+
+ if (cached) {
+ *index = dict_mem_index_create(table_name, name_buf,
+ space, type, n_fields);
+ } else {
+ ut_a(*index);
+
+ dict_mem_fill_index_struct(*index, NULL, NULL, name_buf,
+ space, type, n_fields);
+ }
+
+ (*index)->id = id;
+ (*index)->page = mach_read_from_4(field);
+ ut_ad((*index)->page);
+
+ return(NULL);
}
/********************************************************************//**
@@ -656,27 +1288,17 @@ static
ulint
dict_load_indexes(
/*==============*/
- dict_table_t* table, /*!< in: table */
+ dict_table_t* table, /*!< in/out: table */
mem_heap_t* heap) /*!< in: memory heap for temporary storage */
{
dict_table_t* sys_indexes;
dict_index_t* sys_index;
- dict_index_t* index;
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
const rec_t* rec;
- const byte* field;
- ulint len;
- ulint name_len;
- char* name_buf;
- ulint type;
- ulint space;
- ulint page_no;
- ulint n_fields;
byte* buf;
ibool is_sys_table;
- dulint id;
mtr_t mtr;
ulint error = DB_SUCCESS;
@@ -694,6 +1316,8 @@ dict_load_indexes(
sys_indexes = dict_table_get_low("SYS_INDEXES");
sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);
ut_a(!dict_table_is_comp(sys_indexes));
+ ut_a(name_of_col_is(sys_indexes, sys_index, 4, "NAME"));
+ ut_a(name_of_col_is(sys_indexes, sys_index, 8, "PAGE_NO"));
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
@@ -707,6 +1331,9 @@ dict_load_indexes(
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
for (;;) {
+ dict_index_t* index;
+ const char* err_msg;
+
if (!btr_pcur_is_on_user_rec(&pcur)) {
break;
@@ -714,90 +1341,73 @@ dict_load_indexes(
rec = btr_pcur_get_rec(&pcur);
- field = rec_get_nth_field_old(rec, 0, &len);
- ut_ad(len == 8);
+ err_msg = dict_load_index_low(buf, table->name, heap, rec,
+ TRUE, &index);
+ ut_ad((index == NULL) == (err_msg != NULL));
- if (ut_memcmp(buf, field, len) != 0) {
+ if (err_msg == dict_load_index_id_err) {
+ /* TABLE_ID mismatch means that we have
+ run out of index definitions for the table. */
break;
- } else if (rec_get_deleted_flag(rec, 0)) {
- /* Skip delete marked records */
+ } else if (err_msg == dict_load_index_del) {
+ /* Skip delete-marked records. */
goto next_rec;
+ } else if (err_msg) {
+ fprintf(stderr, "InnoDB: %s\n", err_msg);
+ error = DB_CORRUPTION;
+ goto func_exit;
}
- field = rec_get_nth_field_old(rec, 1, &len);
- ut_ad(len == 8);
- id = mach_read_from_8(field);
-
- ut_a(name_of_col_is(sys_indexes, sys_index, 4, "NAME"));
-
- field = rec_get_nth_field_old(rec, 4, &name_len);
- name_buf = mem_heap_strdupl(heap, (char*) field, name_len);
-
- field = rec_get_nth_field_old(rec, 5, &len);
- n_fields = mach_read_from_4(field);
-
- field = rec_get_nth_field_old(rec, 6, &len);
- type = mach_read_from_4(field);
-
- field = rec_get_nth_field_old(rec, 7, &len);
- space = mach_read_from_4(field);
-
- ut_a(name_of_col_is(sys_indexes, sys_index, 8, "PAGE_NO"));
-
- field = rec_get_nth_field_old(rec, 8, &len);
- page_no = mach_read_from_4(field);
+ ut_ad(index);
/* We check for unsupported types first, so that the
subsequent checks are relevant for the supported types. */
- if (type & ~(DICT_CLUSTERED | DICT_UNIQUE)) {
+ if (index->type & ~(DICT_CLUSTERED | DICT_UNIQUE)) {
fprintf(stderr,
"InnoDB: Error: unknown type %lu"
" of index %s of table %s\n",
- (ulong) type, name_buf, table->name);
+ (ulong) index->type, index->name, table->name);
error = DB_UNSUPPORTED;
+ dict_mem_index_free(index);
goto func_exit;
- } else if (page_no == FIL_NULL) {
+ } else if (index->page == FIL_NULL) {
fprintf(stderr,
"InnoDB: Error: trying to load index %s"
" for table %s\n"
"InnoDB: but the index tree has been freed!\n",
- name_buf, table->name);
+ index->name, table->name);
+corrupted:
+ dict_mem_index_free(index);
error = DB_CORRUPTION;
goto func_exit;
- } else if ((type & DICT_CLUSTERED) == 0
- && NULL == dict_table_get_first_index(table)) {
+ } else if (!dict_index_is_clust(index)
+ && NULL == dict_table_get_first_index(table)) {
fputs("InnoDB: Error: trying to load index ",
stderr);
- ut_print_name(stderr, NULL, FALSE, name_buf);
+ ut_print_name(stderr, NULL, FALSE, index->name);
fputs(" for table ", stderr);
ut_print_name(stderr, NULL, TRUE, table->name);
fputs("\nInnoDB: but the first index"
" is not clustered!\n", stderr);
- error = DB_CORRUPTION;
- goto func_exit;
+ goto corrupted;
} else if (is_sys_table
- && ((type & DICT_CLUSTERED)
+ && (dict_index_is_clust(index)
|| ((table == dict_sys->sys_tables)
- && (name_len == (sizeof "ID_IND") - 1)
- && (0 == ut_memcmp(name_buf,
- "ID_IND", name_len))))) {
+ && !strcmp("ID_IND", index->name)))) {
/* The index was created in memory already at booting
of the database server */
+ dict_mem_index_free(index);
} else {
- index = dict_mem_index_create(table->name, name_buf,
- space, type, n_fields);
- index->id = id;
-
dict_load_fields(index, heap);
- error = dict_index_add_to_cache(table, index, page_no,
- FALSE);
+ error = dict_index_add_to_cache(table, index,
+ index->page, FALSE);
/* The data dictionary tables should never contain
invalid index definitions. If we ignored this error
and simply did not load this index definition, the
@@ -821,80 +1431,83 @@ func_exit:
}
/********************************************************************//**
-Loads a table definition and also all its index definitions, and also
-the cluster definition if the table is a member in a cluster. Also loads
-all foreign key constraints where the foreign key is in the table or where
-a foreign key references columns in this table. Adds all these to the data
-dictionary cache.
-@return table, NULL if does not exist; if the table is stored in an
-.ibd file, but the file does not exist, then we set the
-ibd_file_missing flag TRUE in the table object we return */
+Loads a table definition from a SYS_TABLES record to dict_table_t.
+Does not load any columns or indexes.
+@return error message, or NULL on success */
UNIV_INTERN
-dict_table_t*
-dict_load_table(
-/*============*/
- const char* name) /*!< in: table name in the
- databasename/tablename format */
+const char*
+dict_load_table_low(
+/*================*/
+ const char* name, /*!< in: table name */
+ const rec_t* rec, /*!< in: SYS_TABLES record */
+ dict_table_t** table) /*!< out,own: table, or NULL */
{
- ibool ibd_file_missing = FALSE;
- dict_table_t* table;
- dict_table_t* sys_tables;
- btr_pcur_t pcur;
- dict_index_t* sys_index;
- dtuple_t* tuple;
- mem_heap_t* heap;
- dfield_t* dfield;
- const rec_t* rec;
const byte* field;
ulint len;
ulint space;
ulint n_cols;
ulint flags;
- ulint err;
- mtr_t mtr;
- ut_ad(mutex_own(&(dict_sys->mutex)));
+ if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
+ return("delete-marked record in SYS_TABLES");
+ }
- heap = mem_heap_create(32000);
+ if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 10)) {
+ return("wrong number of columns in SYS_TABLES record");
+ }
- mtr_start(&mtr);
+ rec_get_nth_field_offs_old(rec, 0/*NAME*/, &len);
+ if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+err_len:
+ return("incorrect column length in SYS_TABLES");
+ }
+ rec_get_nth_field_offs_old(rec, 1/*DB_TRX_ID*/, &len);
+ if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
+ goto err_len;
+ }
+ rec_get_nth_field_offs_old(rec, 2/*DB_ROLL_PTR*/, &len);
+ if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
+ goto err_len;
+ }
- sys_tables = dict_table_get_low("SYS_TABLES");
- sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
- ut_a(!dict_table_is_comp(sys_tables));
+ rec_get_nth_field_offs_old(rec, 3/*ID*/, &len);
+ if (UNIV_UNLIKELY(len != 8)) {
+ goto err_len;
+ }
- tuple = dtuple_create(heap, 1);
- dfield = dtuple_get_nth_field(tuple, 0);
+ field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
+ }
- dfield_set_data(dfield, name, ut_strlen(name));
- dict_index_copy_types(tuple, sys_index, 1);
+ n_cols = mach_read_from_4(field);
- btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
- BTR_SEARCH_LEAF, &pcur, &mtr);
- rec = btr_pcur_get_rec(&pcur);
+ rec_get_nth_field_offs_old(rec, 5/*TYPE*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
+ }
- if (!btr_pcur_is_on_user_rec(&pcur)
- || rec_get_deleted_flag(rec, 0)) {
- /* Not found */
-err_exit:
- btr_pcur_close(&pcur);
- mtr_commit(&mtr);
- mem_heap_free(heap);
+ rec_get_nth_field_offs_old(rec, 6/*MIX_ID*/, &len);
+ if (UNIV_UNLIKELY(len != 8)) {
+ goto err_len;
+ }
- return(NULL);
+ rec_get_nth_field_offs_old(rec, 7/*MIX_LEN*/, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
}
- field = rec_get_nth_field_old(rec, 0, &len);
+ rec_get_nth_field_offs_old(rec, 8/*CLUSTER_ID*/, &len);
+ if (UNIV_UNLIKELY(len != UNIV_SQL_NULL)) {
+ goto err_len;
+ }
- /* Check if the table name in record is the searched one */
- if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) {
+ field = rec_get_nth_field_old(rec, 9/*SPACE*/, &len);
- goto err_exit;
+ if (UNIV_UNLIKELY(len != 4)) {
+ goto err_len;
}
- ut_a(name_of_col_is(sys_tables, sys_index, 9, "SPACE"));
-
- field = rec_get_nth_field_old(rec, 9, &len);
space = mach_read_from_4(field);
/* Check if the tablespace exists and has the right name */
@@ -902,7 +1515,8 @@ err_exit:
flags = dict_sys_tables_get_flags(rec);
if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) {
- field = rec_get_nth_field_old(rec, 5, &len);
+ field = rec_get_nth_field_old(rec, 5/*TYPE*/, &len);
+ ut_ad(len == 4); /* this was checked earlier */
flags = mach_read_from_4(field);
ut_print_timestamp(stderr);
@@ -912,17 +1526,12 @@ err_exit:
"InnoDB: in InnoDB data dictionary"
" has unknown type %lx.\n",
(ulong) flags);
- goto err_exit;
+ return(NULL);
}
} else {
flags = 0;
}
- ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS"));
-
- field = rec_get_nth_field_old(rec, 4, &len);
- n_cols = mach_read_from_4(field);
-
/* The high-order bit of N_COLS is the "compact format" flag.
For tables in that format, MIX_LEN may hold additional flags. */
if (n_cols & 0x80000000UL) {
@@ -930,9 +1539,13 @@ err_exit:
flags |= DICT_TF_COMPACT;
- ut_a(name_of_col_is(sys_tables, sys_index, 7, "MIX_LEN"));
field = rec_get_nth_field_old(rec, 7, &len);
+ if (UNIV_UNLIKELY(len != 4)) {
+
+ goto err_len;
+ }
+
flags2 = mach_read_from_4(field);
if (flags2 & (~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT))) {
@@ -951,53 +1564,145 @@ err_exit:
}
/* See if the tablespace is available. */
- if (space == 0) {
+ *table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL,
+ flags);
+
+ field = rec_get_nth_field_old(rec, 3/*ID*/, &len);
+ ut_ad(len == 8); /* this was checked earlier */
+
+ (*table)->id = mach_read_from_8(field);
+
+ (*table)->ibd_file_missing = FALSE;
+
+ return(NULL);
+}
+
+/********************************************************************//**
+Loads a table definition and also all its index definitions, and also
+the cluster definition if the table is a member in a cluster. Also loads
+all foreign key constraints where the foreign key is in the table or where
+a foreign key references columns in this table. Adds all these to the data
+dictionary cache.
+@return table, NULL if does not exist; if the table is stored in an
+.ibd file, but the file does not exist, then we set the
+ibd_file_missing flag TRUE in the table object we return */
+UNIV_INTERN
+dict_table_t*
+dict_load_table(
+/*============*/
+ const char* name, /*!< in: table name in the
+ databasename/tablename format */
+ ibool cached) /*!< in: TRUE=add to cache, FALSE=do not */
+{
+ dict_table_t* table;
+ dict_table_t* sys_tables;
+ btr_pcur_t pcur;
+ dict_index_t* sys_index;
+ dtuple_t* tuple;
+ mem_heap_t* heap;
+ dfield_t* dfield;
+ const rec_t* rec;
+ const byte* field;
+ ulint len;
+ ulint err;
+ const char* err_msg;
+ mtr_t mtr;
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ heap = mem_heap_create(32000);
+
+ mtr_start(&mtr);
+
+ sys_tables = dict_table_get_low("SYS_TABLES");
+ sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
+ ut_a(!dict_table_is_comp(sys_tables));
+ ut_a(name_of_col_is(sys_tables, sys_index, 3, "ID"));
+ ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS"));
+ ut_a(name_of_col_is(sys_tables, sys_index, 5, "TYPE"));
+ ut_a(name_of_col_is(sys_tables, sys_index, 7, "MIX_LEN"));
+ ut_a(name_of_col_is(sys_tables, sys_index, 9, "SPACE"));
+
+ tuple = dtuple_create(heap, 1);
+ dfield = dtuple_get_nth_field(tuple, 0);
+
+ dfield_set_data(dfield, name, ut_strlen(name));
+ dict_index_copy_types(tuple, sys_index, 1);
+
+ btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
+ BTR_SEARCH_LEAF, &pcur, &mtr);
+ rec = btr_pcur_get_rec(&pcur);
+
+ if (!btr_pcur_is_on_user_rec(&pcur)
+ || rec_get_deleted_flag(rec, 0)) {
+ /* Not found */
+err_exit:
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+ mem_heap_free(heap);
+
+ return(NULL);
+ }
+
+ field = rec_get_nth_field_old(rec, 0, &len);
+
+ /* Check if the table name in record is the searched one */
+ if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) {
+
+ goto err_exit;
+ }
+
+ err_msg = dict_load_table_low(name, rec, &table);
+
+ if (err_msg) {
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: %s\n", err_msg);
+ goto err_exit;
+ }
+
+ if (table->space == 0) {
/* The system tablespace is always available. */
} else if (!fil_space_for_table_exists_in_mem(
- space, name,
- (flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY,
+ table->space, name,
+ (table->flags >> DICT_TF2_SHIFT)
+ & DICT_TF2_TEMPORARY,
FALSE, FALSE)) {
- if ((flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY) {
+ if (table->flags & (DICT_TF2_TEMPORARY << DICT_TF2_SHIFT)) {
/* Do not bother to retry opening temporary tables. */
- ibd_file_missing = TRUE;
+ table->ibd_file_missing = TRUE;
} else {
ut_print_timestamp(stderr);
fprintf(stderr,
- " InnoDB: error: space object of table");
+ " InnoDB: error: space object of table ");
ut_print_filename(stderr, name);
fprintf(stderr, ",\n"
"InnoDB: space id %lu did not exist in memory."
" Retrying an open.\n",
- (ulong) space);
+ (ulong) table->space);
/* Try to open the tablespace */
if (!fil_open_single_table_tablespace(
- TRUE, space,
- flags & ~(~0 << DICT_TF_BITS), name)) {
+ TRUE, table->space,
+ table->flags & ~(~0 << DICT_TF_BITS), name)) {
/* We failed to find a sensible
tablespace file */
- ibd_file_missing = TRUE;
+ table->ibd_file_missing = TRUE;
}
}
}
- table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL,
- flags);
-
- table->ibd_file_missing = (unsigned int) ibd_file_missing;
-
- ut_a(name_of_col_is(sys_tables, sys_index, 3, "ID"));
-
- field = rec_get_nth_field_old(rec, 3, &len);
- table->id = mach_read_from_8(field);
-
btr_pcur_close(&pcur);
mtr_commit(&mtr);
dict_load_columns(table, heap);
- dict_table_add_to_cache(table, heap);
+ if (cached) {
+ dict_table_add_to_cache(table, heap);
+ } else {
+ dict_table_add_system_columns(table, heap);
+ }
mem_heap_empty(heap);
@@ -1007,7 +1712,8 @@ err_exit:
of the error condition, since the user may want to dump data from the
clustered index. However we load the foreign key information only if
all indexes were loaded. */
- if (err == DB_SUCCESS) {
+ if (!cached) {
+ } else if (err == DB_SUCCESS) {
err = dict_load_foreigns(table->name, TRUE);
} else if (!srv_force_recovery) {
dict_table_remove_from_cache(table);
@@ -1124,7 +1830,8 @@ dict_load_table_on_id(
/* Now we get the table name from the record */
field = rec_get_nth_field_old(rec, 1, &len);
/* Load the table definition to memory */
- table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len));
+ table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len),
+ TRUE);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
diff --git a/storage/innobase/dict/dict0mem.c b/storage/innobase/dict/dict0mem.c
index b2f58fbc63f..b6e516783c7 100644
--- a/storage/innobase/dict/dict0mem.c
+++ b/storage/innobase/dict/dict0mem.c
@@ -177,10 +177,6 @@ dict_mem_table_add_col(
ulint len) /*!< in: precision */
{
dict_col_t* col;
-#ifndef UNIV_HOTBACKUP
- ulint mbminlen;
- ulint mbmaxlen;
-#endif /* !UNIV_HOTBACKUP */
ulint i;
ut_ad(table);
@@ -205,19 +201,7 @@ dict_mem_table_add_col(
col = dict_table_get_nth_col(table, i);
- col->ind = (unsigned int) i;
- col->ord_part = 0;
-
- col->mtype = (unsigned int) mtype;
- col->prtype = (unsigned int) prtype;
- col->len = (unsigned int) len;
-
-#ifndef UNIV_HOTBACKUP
- dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen);
-
- col->mbminlen = (unsigned int) mbminlen;
- col->mbmaxlen = (unsigned int) mbmaxlen;
-#endif /* !UNIV_HOTBACKUP */
+ dict_mem_fill_column_struct(col, i, mtype, prtype, len);
}
/**********************************************************************//**
@@ -244,22 +228,9 @@ dict_mem_index_create(
heap = mem_heap_create(DICT_HEAP_SIZE);
index = mem_heap_zalloc(heap, sizeof(dict_index_t));
- index->heap = heap;
+ dict_mem_fill_index_struct(index, heap, table_name, index_name,
+ space, type, n_fields);
- index->type = type;
-#ifndef UNIV_HOTBACKUP
- index->space = (unsigned int) space;
-#endif /* !UNIV_HOTBACKUP */
- index->name = mem_heap_strdup(heap, index_name);
- index->table_name = table_name;
- index->n_fields = (unsigned int) n_fields;
- index->fields = mem_heap_alloc(heap, 1 + n_fields
- * sizeof(dict_field_t));
- /* The '1 +' above prevents allocation
- of an empty mem block */
-#ifdef UNIV_DEBUG
- index->magic_n = DICT_INDEX_MAGIC_N;
-#endif /* UNIV_DEBUG */
return(index);
}
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 12561c8c2a6..710841daf55 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -11105,7 +11105,15 @@ i_s_innodb_lock_waits,
i_s_innodb_cmp,
i_s_innodb_cmp_reset,
i_s_innodb_cmpmem,
-i_s_innodb_cmpmem_reset
+i_s_innodb_cmpmem_reset,
+i_s_innodb_sys_tables,
+i_s_innodb_sys_tablestats,
+i_s_innodb_sys_indexes,
+i_s_innodb_sys_columns,
+i_s_innodb_sys_fields,
+i_s_innodb_sys_foreign,
+i_s_innodb_sys_foreign_cols
+
mysql_declare_plugin_end;
/** @brief Initialize the default value of innodb_commit_concurrency.
diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
index f8b3b71c804..e48ea76012d 100644
--- a/storage/innobase/handler/i_s.cc
+++ b/storage/innobase/handler/i_s.cc
@@ -36,12 +36,17 @@ Created July 18, 2007 Vasil Dimov
#include <mysql/innodb_priv.h>
extern "C" {
-#include "trx0i_s.h"
-#include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */
+#include "btr0pcur.h" /* for file sys_tables related info. */
+#include "btr0types.h"
#include "buf0buddy.h" /* for i_s_cmpmem */
#include "buf0buf.h" /* for buf_pool and PAGE_ZIP_MIN_SIZE */
+#include "dict0load.h" /* for file sys_tables related info. */
+#include "dict0mem.h"
+#include "dict0types.h"
#include "ha_prototypes.h" /* for innobase_convert_name() */
#include "srv0start.h" /* for srv_was_started */
+#include "trx0i_s.h"
+#include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */
}
static const char plugin_author[] = "Innobase Oy";
@@ -131,7 +136,6 @@ int
i_s_common_deinit(
/*==============*/
void* p); /*!< in/out: table schema object */
-
/*******************************************************************//**
Auxiliary function to store time_t value in MYSQL_TYPE_DATETIME
field.
@@ -1905,3 +1909,1660 @@ i_s_common_deinit(
DBUG_RETURN(0);
}
+
+/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLES */
+static ST_FIELD_INFO innodb_sys_tables_fields_info[] =
+{
+#define SYS_TABLE_ID 0
+ {STRUCT_FLD(field_name, "TABLE_ID"),
+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_TABLE_NAME 1
+ {STRUCT_FLD(field_name, "NAME"),
+ STRUCT_FLD(field_length, NAME_LEN + 1),
+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_TABLE_FLAG 2
+ {STRUCT_FLD(field_name, "FLAG"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_TABLE_NUM_COLUMN 3
+ {STRUCT_FLD(field_name, "N_COLS"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_TABLE_SPACE 4
+ {STRUCT_FLD(field_name, "SPACE"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+ END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+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 */
+{
+ longlong table_id;
+ Field** fields;
+
+ DBUG_ENTER("i_s_dict_fill_sys_tables");
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ fields = table_to_fill->field;
+
+ table_id = ut_conv_dulint_to_longlong(table->id);
+
+ OK(fields[SYS_TABLE_ID]->store(table_id));
+
+ OK(field_store_string(fields[SYS_TABLE_NAME], table->name));
+
+ OK(fields[SYS_TABLE_FLAG]->store(table->flags));
+
+ OK(fields[SYS_TABLE_NUM_COLUMN]->store(table->n_cols));
+
+ OK(fields[SYS_TABLE_SPACE]->store(table->space));
+
+ 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_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 */
+ COND* cond) /*!< in: condition (not used) */
+{
+ btr_pcur_t pcur;
+ const rec_t* rec;
+ mem_heap_t* heap;
+ mtr_t mtr;
+
+ DBUG_ENTER("i_s_sys_tables_fill_table");
+
+ /* deny access to non-superusers */
+ if (check_global_access(thd, PROCESS_ACL)) {
+
+ DBUG_RETURN(0);
+ }
+
+ heap = mem_heap_create(1000);
+ mutex_enter(&(dict_sys->mutex));
+ mtr_start(&mtr);
+
+ rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
+
+ while (rec) {
+ 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 = dict_process_sys_tables_rec(
+ heap, rec, &table_rec, DICT_TABLE_LOAD_FROM_RECORD);
+
+ mtr_commit(&mtr);
+ mutex_exit(&dict_sys->mutex);
+
+ if (!err_msg) {
+ i_s_dict_fill_sys_tables(thd, table_rec, tables->table);
+ } else {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_CANT_FIND_SYSTEM_REC,
+ err_msg);
+ }
+
+ /* Since dict_process_sys_tables_rec() is called with
+ DICT_TABLE_LOAD_FROM_RECORD, the table_rec is created in
+ dict_process_sys_tables_rec(), we will need to free it */
+ if (table_rec) {
+ dict_mem_table_free(table_rec);
+ }
+
+ mem_heap_empty(heap);
+
+ /* Get the next record */
+ mutex_enter(&dict_sys->mutex);
+ mtr_start(&mtr);
+ rec = dict_getnext_system(&pcur, &mtr);
+ }
+
+ mtr_commit(&mtr);
+ mutex_exit(&dict_sys->mutex);
+ mem_heap_free(heap);
+
+ 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 = innodb_sys_tables_fields_info;
+ schema->fill_table = i_s_sys_tables_fill_table;
+
+ DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_tables =
+{
+ /* the plugin type (a MYSQL_XXX_PLUGIN value) */
+ /* int */
+ STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
+
+ /* pointer to type-specific plugin descriptor */
+ /* void* */
+ STRUCT_FLD(info, &i_s_info),
+
+ /* plugin name */
+ /* const char* */
+ STRUCT_FLD(name, "INNODB_SYS_TABLES"),
+
+ /* plugin author (for SHOW PLUGINS) */
+ /* const char* */
+ STRUCT_FLD(author, plugin_author),
+
+ /* general descriptive text (for SHOW PLUGINS) */
+ /* const char* */
+ STRUCT_FLD(descr, "InnoDB SYS_TABLES"),
+
+ /* the plugin license (PLUGIN_LICENSE_XXX) */
+ /* int */
+ STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
+
+ /* the function to invoke when plugin is loaded */
+ /* int (*)(void*); */
+ STRUCT_FLD(init, innodb_sys_tables_init),
+
+ /* the function to invoke when plugin is unloaded */
+ /* int (*)(void*); */
+ STRUCT_FLD(deinit, i_s_common_deinit),
+
+ /* plugin version (for SHOW PLUGINS) */
+ /* unsigned int */
+ STRUCT_FLD(version, INNODB_VERSION_SHORT),
+
+ /* struct st_mysql_show_var* */
+ STRUCT_FLD(status_vars, NULL),
+
+ /* struct st_mysql_sys_var** */
+ STRUCT_FLD(system_vars, NULL),
+
+ /* reserved for dependency checking */
+ /* void* */
+ STRUCT_FLD(__reserved1, NULL)
+};
+
+/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLESTATS */
+static ST_FIELD_INFO innodb_sys_tablestats_fields_info[] =
+{
+#define SYS_TABLESTATS_ID 0
+ {STRUCT_FLD(field_name, "TABLE_ID"),
+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_NAME 1
+ {STRUCT_FLD(field_name, "NAME"),
+ STRUCT_FLD(field_length, NAME_LEN + 1),
+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_INIT 2
+ {STRUCT_FLD(field_name, "STATS_INITIALIZED"),
+ STRUCT_FLD(field_length, NAME_LEN + 1),
+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_NROW 3
+ {STRUCT_FLD(field_name, "NUM_ROWS"),
+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_CLUST_SIZE 4
+ {STRUCT_FLD(field_name, "CLUST_INDEX_SIZE"),
+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_INDEX_SIZE 5
+ {STRUCT_FLD(field_name, "OTHER_INDEX_SIZE"),
+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_MODIFIED 6
+ {STRUCT_FLD(field_name, "MODIFIED_COUNTER"),
+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_AUTONINC 7
+ {STRUCT_FLD(field_name, "AUTOINC"),
+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_MYSQL_OPEN_HANDLE 8
+ {STRUCT_FLD(field_name, "MYSQL_HANDLES_OPENED"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+ END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+Populate information_schema.innodb_sys_tablestats table with information
+from SYS_TABLES.
+@return 0 on success */
+static
+int
+i_s_dict_fill_sys_tablestats(
+/*=========================*/
+ THD* thd, /*!< in: thread */
+ dict_table_t* table, /*!< in: table */
+ TABLE* table_to_fill) /*!< in/out: fill this table */
+{
+ longlong table_id;
+ Field** fields;
+
+ DBUG_ENTER("i_s_dict_fill_sys_tablestats");
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ fields = table_to_fill->field;
+
+ table_id = ut_conv_dulint_to_longlong(table->id);
+
+ OK(fields[SYS_TABLESTATS_ID]->store(table_id));
+
+ OK(field_store_string(fields[SYS_TABLESTATS_NAME], table->name));
+
+ if (table->stat_initialized) {
+ OK(field_store_string(fields[SYS_TABLESTATS_INIT],
+ "Initialized"));
+ } else {
+ OK(field_store_string(fields[SYS_TABLESTATS_INIT],
+ "Uninitialized"));
+ }
+
+ OK(fields[SYS_TABLESTATS_NROW]->store(table->stat_n_rows));
+
+ OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(
+ table->stat_clustered_index_size));
+
+ OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(
+ table->stat_sum_of_other_index_sizes));
+
+ OK(fields[SYS_TABLESTATS_MODIFIED]->store(
+ table->stat_modified_counter));
+
+ OK(fields[SYS_TABLESTATS_AUTONINC]->store(table->autoinc));
+
+ OK(fields[SYS_TABLESTATS_MYSQL_OPEN_HANDLE]->store(
+ table->n_mysql_handles_opened));
+
+ 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 */
+ COND* cond) /*!< in: condition (not used) */
+{
+ btr_pcur_t pcur;
+ const rec_t* rec;
+ mem_heap_t* heap;
+ mtr_t mtr;
+
+ DBUG_ENTER("i_s_sys_tables_fill_table_stats");
+
+ /* deny access to non-superusers */
+ if (check_global_access(thd, PROCESS_ACL)) {
+
+ DBUG_RETURN(0);
+ }
+
+ heap = mem_heap_create(1000);
+ mutex_enter(&dict_sys->mutex);
+ mtr_start(&mtr);
+
+ rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
+
+ while (rec) {
+ const char* err_msg;
+ dict_table_t* table_rec;
+
+ /* Fetch the dict_table_t structure corresponding to
+ this SYS_TABLES record */
+ err_msg = dict_process_sys_tables_rec(
+ heap, rec, &table_rec, DICT_TABLE_LOAD_FROM_CACHE);
+
+ mtr_commit(&mtr);
+ mutex_exit(&dict_sys->mutex);
+
+ if (!err_msg) {
+ i_s_dict_fill_sys_tablestats(thd, table_rec,
+ tables->table);
+ } else {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_CANT_FIND_SYSTEM_REC,
+ err_msg);
+ }
+
+ mem_heap_empty(heap);
+
+ /* Get the next record */
+ mutex_enter(&dict_sys->mutex);
+ mtr_start(&mtr);
+ rec = dict_getnext_system(&pcur, &mtr);
+ }
+
+ mtr_commit(&mtr);
+ mutex_exit(&dict_sys->mutex);
+ mem_heap_free(heap);
+
+ 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 = innodb_sys_tablestats_fields_info;
+ schema->fill_table = i_s_sys_tables_fill_table_stats;
+
+ DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_tablestats =
+{
+ /* the plugin type (a MYSQL_XXX_PLUGIN value) */
+ /* int */
+ STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
+
+ /* pointer to type-specific plugin descriptor */
+ /* void* */
+ STRUCT_FLD(info, &i_s_info),
+
+ /* plugin name */
+ /* const char* */
+ STRUCT_FLD(name, "INNODB_SYS_TABLESTATS"),
+
+ /* plugin author (for SHOW PLUGINS) */
+ /* const char* */
+ STRUCT_FLD(author, plugin_author),
+
+ /* general descriptive text (for SHOW PLUGINS) */
+ /* const char* */
+ STRUCT_FLD(descr, "InnoDB SYS_TABLESTATS"),
+
+ /* the plugin license (PLUGIN_LICENSE_XXX) */
+ /* int */
+ STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
+
+ /* the function to invoke when plugin is loaded */
+ /* int (*)(void*); */
+ STRUCT_FLD(init, innodb_sys_tablestats_init),
+
+ /* the function to invoke when plugin is unloaded */
+ /* int (*)(void*); */
+ STRUCT_FLD(deinit, i_s_common_deinit),
+
+ /* plugin version (for SHOW PLUGINS) */
+ /* unsigned int */
+ STRUCT_FLD(version, INNODB_VERSION_SHORT),
+
+ /* struct st_mysql_show_var* */
+ STRUCT_FLD(status_vars, NULL),
+
+ /* struct st_mysql_sys_var** */
+ STRUCT_FLD(system_vars, NULL),
+
+ /* reserved for dependency checking */
+ /* void* */
+ STRUCT_FLD(__reserved1, NULL)
+};
+
+/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_INDEXES */
+static ST_FIELD_INFO innodb_sysindex_fields_info[] =
+{
+#define SYS_INDEX_ID 0
+ {STRUCT_FLD(field_name, "INDEX_ID"),
+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_INDEX_NAME 1
+ {STRUCT_FLD(field_name, "NAME"),
+ STRUCT_FLD(field_length, NAME_LEN + 1),
+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_INDEX_TABLE_ID 2
+ {STRUCT_FLD(field_name, "TABLE_ID"),
+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_INDEX_TYPE 3
+ {STRUCT_FLD(field_name, "TYPE"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_INDEX_NUM_FIELDS 4
+ {STRUCT_FLD(field_name, "N_FIELDS"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_INDEX_PAGE_NO 5
+ {STRUCT_FLD(field_name, "PAGE_NO"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_INDEX_SPACE 6
+ {STRUCT_FLD(field_name, "SPACE"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+ END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+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 */
+ dulint tableid, /*!< in: table id */
+ dict_index_t* index, /*!< in: populated dict_index_t
+ struct with index info */
+ TABLE* table_to_fill) /*!< in/out: fill this table */
+{
+ longlong table_id;
+ longlong index_id;
+ Field** fields;
+
+ DBUG_ENTER("i_s_dict_fill_sys_indexes");
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ fields = table_to_fill->field;
+
+ table_id = ut_conv_dulint_to_longlong(tableid);
+ index_id = ut_conv_dulint_to_longlong(index->id);
+
+ OK(fields[SYS_INDEX_ID]->store(index_id));
+
+ OK(field_store_string(fields[SYS_INDEX_NAME], index->name));
+
+ OK(fields[SYS_INDEX_TABLE_ID]->store(table_id));
+
+ OK(fields[SYS_INDEX_TYPE]->store(index->type));
+
+ OK(fields[SYS_INDEX_NUM_FIELDS]->store(index->n_fields));
+
+ OK(fields[SYS_INDEX_PAGE_NO]->store(index->page));
+
+ OK(fields[SYS_INDEX_SPACE]->store(index->space));
+
+ 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 */
+ COND* cond) /*!< 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");
+
+ /* deny access to non-superusers */
+ if (check_global_access(thd, PROCESS_ACL)) {
+
+ DBUG_RETURN(0);
+ }
+
+ heap = mem_heap_create(1000);
+ mutex_enter(&dict_sys->mutex);
+ mtr_start(&mtr);
+
+ /* Start scan the SYS_INDEXES table */
+ rec = dict_startscan_system(&pcur, &mtr, SYS_INDEXES);
+
+ /* Process each record in the table */
+ while (rec) {
+ const char* err_msg;;
+ dulint table_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);
+
+ mtr_commit(&mtr);
+ mutex_exit(&dict_sys->mutex);
+
+ if (!err_msg) {
+ i_s_dict_fill_sys_indexes(thd, table_id, &index_rec,
+ tables->table);
+ } else {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_CANT_FIND_SYSTEM_REC,
+ err_msg);
+ }
+
+ mem_heap_empty(heap);
+
+ /* Get the next record */
+ mutex_enter(&dict_sys->mutex);
+ mtr_start(&mtr);
+ rec = dict_getnext_system(&pcur, &mtr);
+ }
+
+ mtr_commit(&mtr);
+ mutex_exit(&dict_sys->mutex);
+ 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_index_init");
+
+ schema = (ST_SCHEMA_TABLE*) p;
+
+ schema->fields_info = innodb_sysindex_fields_info;
+ schema->fill_table = i_s_sys_indexes_fill_table;
+
+ DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_indexes =
+{
+ /* the plugin type (a MYSQL_XXX_PLUGIN value) */
+ /* int */
+ STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
+
+ /* pointer to type-specific plugin descriptor */
+ /* void* */
+ STRUCT_FLD(info, &i_s_info),
+
+ /* plugin name */
+ /* const char* */
+ STRUCT_FLD(name, "INNODB_SYS_INDEXES"),
+
+ /* plugin author (for SHOW PLUGINS) */
+ /* const char* */
+ STRUCT_FLD(author, plugin_author),
+
+ /* general descriptive text (for SHOW PLUGINS) */
+ /* const char* */
+ STRUCT_FLD(descr, "InnoDB SYS_INDEXES"),
+
+ /* the plugin license (PLUGIN_LICENSE_XXX) */
+ /* int */
+ STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
+
+ /* the function to invoke when plugin is loaded */
+ /* int (*)(void*); */
+ STRUCT_FLD(init, innodb_sys_indexes_init),
+
+ /* the function to invoke when plugin is unloaded */
+ /* int (*)(void*); */
+ STRUCT_FLD(deinit, i_s_common_deinit),
+
+ /* plugin version (for SHOW PLUGINS) */
+ /* unsigned int */
+ STRUCT_FLD(version, INNODB_VERSION_SHORT),
+
+ /* struct st_mysql_show_var* */
+ STRUCT_FLD(status_vars, NULL),
+
+ /* struct st_mysql_sys_var** */
+ STRUCT_FLD(system_vars, NULL),
+
+ /* reserved for dependency checking */
+ /* void* */
+ STRUCT_FLD(__reserved1, NULL)
+};
+
+/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_COLUMNS */
+static ST_FIELD_INFO innodb_sys_columns_fields_info[] =
+{
+#define SYS_COLUMN_TABLE_ID 0
+ {STRUCT_FLD(field_name, "TABLE_ID"),
+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_COLUMN_NAME 1
+ {STRUCT_FLD(field_name, "NAME"),
+ STRUCT_FLD(field_length, NAME_LEN + 1),
+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_COLUMN_POSITION 2
+ {STRUCT_FLD(field_name, "POS"),
+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_COLUMN_MTYPE 3
+ {STRUCT_FLD(field_name, "MTYPE"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_COLUMN__PRTYPE 4
+ {STRUCT_FLD(field_name, "PRTYPE"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_COLUMN_COLUMN_LEN 5
+ {STRUCT_FLD(field_name, "LEN"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+ END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+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 */
+ dulint tableid, /*!< in: table ID */
+ const char* col_name, /*!< in: column name */
+ dict_col_t* column, /*!< in: dict_col_t struct holding
+ more column information */
+ TABLE* table_to_fill) /*!< in/out: fill this table */
+{
+ longlong table_id;
+ Field** fields;
+
+ DBUG_ENTER("i_s_dict_fill_sys_columns");
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ fields = table_to_fill->field;
+
+ table_id = ut_conv_dulint_to_longlong(tableid);
+
+ OK(fields[SYS_COLUMN_TABLE_ID]->store(table_id));
+
+ OK(field_store_string(fields[SYS_COLUMN_NAME], col_name));
+
+ OK(fields[SYS_COLUMN_POSITION]->store(column->ind));
+
+ 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 */
+ COND* cond) /*!< 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");
+
+ /* deny access to non-superusers */
+ if (check_global_access(thd, PROCESS_ACL)) {
+
+ DBUG_RETURN(0);
+ }
+
+ heap = mem_heap_create(1000);
+ mutex_enter(&dict_sys->mutex);
+ mtr_start(&mtr);
+
+ rec = dict_startscan_system(&pcur, &mtr, SYS_COLUMNS);
+
+ while (rec) {
+ const char* err_msg;
+ dict_col_t column_rec;
+ dulint table_id;
+
+ /* 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);
+
+ mtr_commit(&mtr);
+ mutex_exit(&dict_sys->mutex);
+
+ if (!err_msg) {
+ i_s_dict_fill_sys_columns(thd, table_id, col_name,
+ &column_rec,
+ tables->table);
+ } else {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_CANT_FIND_SYSTEM_REC,
+ err_msg);
+ }
+
+ mem_heap_empty(heap);
+
+ /* Get the next record */
+ mutex_enter(&dict_sys->mutex);
+ mtr_start(&mtr);
+ rec = dict_getnext_system(&pcur, &mtr);
+ }
+
+ mtr_commit(&mtr);
+ mutex_exit(&dict_sys->mutex);
+ 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 = innodb_sys_columns_fields_info;
+ schema->fill_table = i_s_sys_columns_fill_table;
+
+ DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_columns =
+{
+ /* the plugin type (a MYSQL_XXX_PLUGIN value) */
+ /* int */
+ STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
+
+ /* pointer to type-specific plugin descriptor */
+ /* void* */
+ STRUCT_FLD(info, &i_s_info),
+
+ /* plugin name */
+ /* const char* */
+ STRUCT_FLD(name, "INNODB_SYS_COLUMNS"),
+
+ /* plugin author (for SHOW PLUGINS) */
+ /* const char* */
+ STRUCT_FLD(author, plugin_author),
+
+ /* general descriptive text (for SHOW PLUGINS) */
+ /* const char* */
+ STRUCT_FLD(descr, "InnoDB SYS_COLUMNS"),
+
+ /* the plugin license (PLUGIN_LICENSE_XXX) */
+ /* int */
+ STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
+
+ /* the function to invoke when plugin is loaded */
+ /* int (*)(void*); */
+ STRUCT_FLD(init, innodb_sys_columns_init),
+
+ /* the function to invoke when plugin is unloaded */
+ /* int (*)(void*); */
+ STRUCT_FLD(deinit, i_s_common_deinit),
+
+ /* plugin version (for SHOW PLUGINS) */
+ /* unsigned int */
+ STRUCT_FLD(version, INNODB_VERSION_SHORT),
+
+ /* struct st_mysql_show_var* */
+ STRUCT_FLD(status_vars, NULL),
+
+ /* struct st_mysql_sys_var** */
+ STRUCT_FLD(system_vars, NULL),
+
+ /* reserved for dependency checking */
+ /* void* */
+ STRUCT_FLD(__reserved1, NULL)
+};
+/* 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
+ {STRUCT_FLD(field_name, "INDEX_ID"),
+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_FIELD_NAME 1
+ {STRUCT_FLD(field_name, "NAME"),
+ STRUCT_FLD(field_length, NAME_LEN + 1),
+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_FIELD_POS 2
+ {STRUCT_FLD(field_name, "POS"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+ END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+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 */
+ dulint indexid, /*!< 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 */
+{
+ longlong index_id;
+ Field** fields;
+
+ DBUG_ENTER("i_s_dict_fill_sys_fields");
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ fields = table_to_fill->field;
+
+ index_id = ut_conv_dulint_to_longlong(indexid);
+
+ OK(fields[SYS_FIELD_INDEX_ID]->store(index_id));
+
+ OK(field_store_string(fields[SYS_FIELD_NAME], field->name));
+
+ OK(fields[SYS_FIELD_POS]->store(pos));
+
+ 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 */
+ COND* cond) /*!< in: condition (not used) */
+{
+ btr_pcur_t pcur;
+ const rec_t* rec;
+ mem_heap_t* heap;
+ dulint last_id;
+ mtr_t mtr;
+
+ DBUG_ENTER("i_s_sys_fields_fill_table");
+
+ /* deny access to non-superusers */
+ if (check_global_access(thd, PROCESS_ACL)) {
+
+ DBUG_RETURN(0);
+ }
+
+ heap = mem_heap_create(1000);
+ mutex_enter(&dict_sys->mutex);
+ mtr_start(&mtr);
+
+ /* 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 = ut_dulint_create(0, 0);
+
+ rec = dict_startscan_system(&pcur, &mtr, SYS_FIELDS);
+
+ while (rec) {
+ ulint pos;
+ const char* err_msg;
+ dulint 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(&mtr);
+ mutex_exit(&dict_sys->mutex);
+
+ 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, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_CANT_FIND_SYSTEM_REC,
+ err_msg);
+ }
+
+ mem_heap_empty(heap);
+
+ /* Get the next record */
+ mutex_enter(&dict_sys->mutex);
+ mtr_start(&mtr);
+ rec = dict_getnext_system(&pcur, &mtr);
+ }
+
+ mtr_commit(&mtr);
+ mutex_exit(&dict_sys->mutex);
+ 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 = innodb_sys_fields_fields_info;
+ schema->fill_table = i_s_sys_fields_fill_table;
+
+ DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_fields =
+{
+ /* the plugin type (a MYSQL_XXX_PLUGIN value) */
+ /* int */
+ STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
+
+ /* pointer to type-specific plugin descriptor */
+ /* void* */
+ STRUCT_FLD(info, &i_s_info),
+
+ /* plugin name */
+ /* const char* */
+ STRUCT_FLD(name, "INNODB_SYS_FIELDS"),
+
+ /* plugin author (for SHOW PLUGINS) */
+ /* const char* */
+ STRUCT_FLD(author, plugin_author),
+
+ /* general descriptive text (for SHOW PLUGINS) */
+ /* const char* */
+ STRUCT_FLD(descr, "InnoDB SYS_FIELDS"),
+
+ /* the plugin license (PLUGIN_LICENSE_XXX) */
+ /* int */
+ STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
+
+ /* the function to invoke when plugin is loaded */
+ /* int (*)(void*); */
+ STRUCT_FLD(init, innodb_sys_fields_init),
+
+ /* the function to invoke when plugin is unloaded */
+ /* int (*)(void*); */
+ STRUCT_FLD(deinit, i_s_common_deinit),
+
+ /* plugin version (for SHOW PLUGINS) */
+ /* unsigned int */
+ STRUCT_FLD(version, INNODB_VERSION_SHORT),
+
+ /* struct st_mysql_show_var* */
+ STRUCT_FLD(status_vars, NULL),
+
+ /* struct st_mysql_sys_var** */
+ STRUCT_FLD(system_vars, NULL),
+
+ /* reserved for dependency checking */
+ /* void* */
+ STRUCT_FLD(__reserved1, NULL)
+};
+
+/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign */
+static ST_FIELD_INFO innodb_sys_foreign_fields_info[] =
+{
+#define SYS_FOREIGN_ID 0
+ {STRUCT_FLD(field_name, "ID"),
+ STRUCT_FLD(field_length, NAME_LEN + 1),
+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_FOREIGN_FOR_NAME 1
+ {STRUCT_FLD(field_name, "FOR_NAME"),
+ STRUCT_FLD(field_length, NAME_LEN + 1),
+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_FOREIGN_REF_NAME 2
+ {STRUCT_FLD(field_name, "REF_NAME"),
+ STRUCT_FLD(field_length, NAME_LEN + 1),
+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_FOREIGN_NUM_COL 3
+ {STRUCT_FLD(field_name, "N_COLS"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_FOREIGN_TYPE 4
+ {STRUCT_FLD(field_name, "TYPE"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+ END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+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");
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ 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 */
+ COND* cond) /*!< 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");
+
+ /* deny access to non-superusers */
+ if (check_global_access(thd, PROCESS_ACL)) {
+
+ DBUG_RETURN(0);
+ }
+
+ heap = mem_heap_create(1000);
+ mutex_enter(&dict_sys->mutex);
+ mtr_start(&mtr);
+
+ rec = dict_startscan_system(&pcur, &mtr, 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(&mtr);
+ mutex_exit(&dict_sys->mutex);
+
+ if (!err_msg) {
+ i_s_dict_fill_sys_foreign(thd, &foreign_rec,
+ tables->table);
+ } else {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_CANT_FIND_SYSTEM_REC,
+ err_msg);
+ }
+
+ mem_heap_empty(heap);
+
+ /* Get the next record */
+ mtr_start(&mtr);
+ mutex_enter(&dict_sys->mutex);
+ rec = dict_getnext_system(&pcur, &mtr);
+ }
+
+ mtr_commit(&mtr);
+ mutex_exit(&dict_sys->mutex);
+ 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 = innodb_sys_foreign_fields_info;
+ schema->fill_table = i_s_sys_foreign_fill_table;
+
+ DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_foreign =
+{
+ /* the plugin type (a MYSQL_XXX_PLUGIN value) */
+ /* int */
+ STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
+
+ /* pointer to type-specific plugin descriptor */
+ /* void* */
+ STRUCT_FLD(info, &i_s_info),
+
+ /* plugin name */
+ /* const char* */
+ STRUCT_FLD(name, "INNODB_SYS_FOREIGN"),
+
+ /* plugin author (for SHOW PLUGINS) */
+ /* const char* */
+ STRUCT_FLD(author, plugin_author),
+
+ /* general descriptive text (for SHOW PLUGINS) */
+ /* const char* */
+ STRUCT_FLD(descr, "InnoDB SYS_FOREIGN"),
+
+ /* the plugin license (PLUGIN_LICENSE_XXX) */
+ /* int */
+ STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
+
+ /* the function to invoke when plugin is loaded */
+ /* int (*)(void*); */
+ STRUCT_FLD(init, innodb_sys_foreign_init),
+
+ /* the function to invoke when plugin is unloaded */
+ /* int (*)(void*); */
+ STRUCT_FLD(deinit, i_s_common_deinit),
+
+ /* plugin version (for SHOW PLUGINS) */
+ /* unsigned int */
+ STRUCT_FLD(version, INNODB_VERSION_SHORT),
+
+ /* struct st_mysql_show_var* */
+ STRUCT_FLD(status_vars, NULL),
+
+ /* struct st_mysql_sys_var** */
+ STRUCT_FLD(system_vars, NULL),
+
+ /* reserved for dependency checking */
+ /* void* */
+ STRUCT_FLD(__reserved1, NULL)
+};
+/* 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
+ {STRUCT_FLD(field_name, "ID"),
+ STRUCT_FLD(field_length, NAME_LEN + 1),
+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_FOREIGN_COL_FOR_NAME 1
+ {STRUCT_FLD(field_name, "FOR_COL_NAME"),
+ STRUCT_FLD(field_length, NAME_LEN + 1),
+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_FOREIGN_COL_REF_NAME 2
+ {STRUCT_FLD(field_name, "REF_COL_NAME"),
+ STRUCT_FLD(field_length, NAME_LEN + 1),
+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, 0),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+#define SYS_FOREIGN_COL_POS 3
+ {STRUCT_FLD(field_name, "POS"),
+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
+ STRUCT_FLD(value, 0),
+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
+ STRUCT_FLD(old_name, ""),
+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
+
+ END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+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");
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ 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));
+
+ 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 */
+ COND* cond) /*!< 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");
+
+ /* deny access to non-superusers */
+ if (check_global_access(thd, PROCESS_ACL)) {
+ DBUG_RETURN(0);
+ }
+
+ heap = mem_heap_create(1000);
+ mutex_enter(&dict_sys->mutex);
+ mtr_start(&mtr);
+
+ rec = dict_startscan_system(&pcur, &mtr, 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(&mtr);
+ mutex_exit(&dict_sys->mutex);
+
+ 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, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_CANT_FIND_SYSTEM_REC,
+ err_msg);
+ }
+
+ mem_heap_empty(heap);
+
+ /* Get the next record */
+ mutex_enter(&dict_sys->mutex);
+ mtr_start(&mtr);
+ rec = dict_getnext_system(&pcur, &mtr);
+ }
+
+ mtr_commit(&mtr);
+ mutex_exit(&dict_sys->mutex);
+ 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 = innodb_sys_foreign_cols_fields_info;
+ schema->fill_table = i_s_sys_foreign_cols_fill_table;
+
+ DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_foreign_cols =
+{
+ /* the plugin type (a MYSQL_XXX_PLUGIN value) */
+ /* int */
+ STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
+
+ /* pointer to type-specific plugin descriptor */
+ /* void* */
+ STRUCT_FLD(info, &i_s_info),
+
+ /* plugin name */
+ /* const char* */
+ STRUCT_FLD(name, "INNODB_SYS_FOREIGN_COLS"),
+
+ /* plugin author (for SHOW PLUGINS) */
+ /* const char* */
+ STRUCT_FLD(author, plugin_author),
+
+ /* general descriptive text (for SHOW PLUGINS) */
+ /* const char* */
+ STRUCT_FLD(descr, "InnoDB SYS_FOREIGN_COLS"),
+
+ /* the plugin license (PLUGIN_LICENSE_XXX) */
+ /* int */
+ STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
+
+ /* the function to invoke when plugin is loaded */
+ /* int (*)(void*); */
+ STRUCT_FLD(init, innodb_sys_foreign_cols_init),
+
+ /* the function to invoke when plugin is unloaded */
+ /* int (*)(void*); */
+ STRUCT_FLD(deinit, i_s_common_deinit),
+
+ /* plugin version (for SHOW PLUGINS) */
+ /* unsigned int */
+ STRUCT_FLD(version, INNODB_VERSION_SHORT),
+
+ /* struct st_mysql_show_var* */
+ STRUCT_FLD(status_vars, NULL),
+
+ /* struct st_mysql_sys_var** */
+ STRUCT_FLD(system_vars, NULL),
+
+ /* reserved for dependency checking */
+ /* void* */
+ STRUCT_FLD(__reserved1, NULL)
+};
+
diff --git a/storage/innobase/handler/i_s.h b/storage/innobase/handler/i_s.h
index 402c88bbedb..69f5ed9dad8 100644
--- a/storage/innobase/handler/i_s.h
+++ b/storage/innobase/handler/i_s.h
@@ -33,5 +33,12 @@ extern struct st_mysql_plugin i_s_innodb_cmp;
extern struct st_mysql_plugin i_s_innodb_cmp_reset;
extern struct st_mysql_plugin i_s_innodb_cmpmem;
extern struct st_mysql_plugin i_s_innodb_cmpmem_reset;
+extern struct st_mysql_plugin i_s_innodb_sys_tables;
+extern struct st_mysql_plugin i_s_innodb_sys_tablestats;
+extern struct st_mysql_plugin i_s_innodb_sys_indexes;
+extern struct st_mysql_plugin i_s_innodb_sys_columns;
+extern struct st_mysql_plugin i_s_innodb_sys_fields;
+extern struct st_mysql_plugin i_s_innodb_sys_foreign;
+extern struct st_mysql_plugin i_s_innodb_sys_foreign_cols;
#endif /* i_s_h */
diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic
index 46e78df8272..93c3f8d4733 100644
--- a/storage/innobase/include/dict0dict.ic
+++ b/storage/innobase/include/dict0dict.ic
@@ -765,7 +765,7 @@ dict_table_get_low(
table = dict_table_check_if_in_cache_low(table_name);
if (table == NULL) {
- table = dict_load_table(table_name);
+ table = dict_load_table(table_name, TRUE);
}
ut_ad(!table || table->cached);
diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h
index 60b8c1fb632..d85f8f7fc3e 100644
--- a/storage/innobase/include/dict0load.h
+++ b/storage/innobase/include/dict0load.h
@@ -31,6 +31,35 @@ Created 4/24/1996 Heikki Tuuri
#include "dict0types.h"
#include "ut0byte.h"
#include "mem0mem.h"
+#include "btr0types.h"
+
+/** enum that defines all 6 system table IDs */
+enum dict_system_table_id {
+ SYS_TABLES = 0,
+ SYS_INDEXES,
+ SYS_COLUMNS,
+ SYS_FIELDS,
+ SYS_FOREIGN,
+ SYS_FOREIGN_COLS,
+
+ /* This must be last item. Defines the number of system tables. */
+ SYS_NUM_SYSTEM_TABLES
+};
+
+typedef enum dict_system_table_id dict_system_id_t;
+
+/** Status bit for dict_process_sys_tables_rec() */
+enum dict_table_info {
+ DICT_TABLE_LOAD_FROM_RECORD = 0,/*!< Directly populate a dict_table_t
+ structure with information from
+ a SYS_TABLES record */
+ DICT_TABLE_LOAD_FROM_CACHE = 1, /*!< Check first whether dict_table_t
+ is in the cache, if so, return it */
+ DICT_TABLE_UPDATE_STATS = 2 /*!< whether to update statistics
+ when loading SYS_TABLES information. */
+};
+
+typedef enum dict_table_info dict_table_info_t;
/********************************************************************//**
In a crash recovery we already have all the tablespace objects created.
@@ -54,6 +83,74 @@ char*
dict_get_first_table_name_in_db(
/*============================*/
const char* name); /*!< in: database name which ends to '/' */
+
+/********************************************************************//**
+Loads a table definition from a SYS_TABLES record to dict_table_t.
+Does not load any columns or indexes.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_load_table_low(
+/*================*/
+ const char* name, /*!< in: table name */
+ const rec_t* rec, /*!< in: SYS_TABLES record */
+ dict_table_t** table); /*!< out,own: table, or NULL */
+/********************************************************************//**
+Loads a table column definition from a SYS_COLUMNS record to
+dict_table_t.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_load_column_low(
+/*=================*/
+ dict_table_t* table, /*!< in/out: table, could be NULL
+ if we just populate a dict_column_t
+ struct with information from
+ a SYS_COLUMNS record */
+ mem_heap_t* heap, /*!< in/out: memory heap
+ for temporary storage */
+ dict_col_t* column, /*!< out: dict_column_t to fill */
+ dulint* table_id, /*!< out: table id */
+ const char** col_name, /*!< out: column name */
+ const rec_t* rec); /*!< in: SYS_COLUMNS record */
+/********************************************************************//**
+Loads an index definition from a SYS_INDEXES record to dict_index_t.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_load_index_low(
+/*================*/
+ byte* table_id, /*!< in/out: table id (8 bytes_,
+ an "in" value if cached=TRUE
+ and "out" when cached=FALSE */
+ const char* table_name, /*!< in: table name */
+ mem_heap_t* heap, /*!< in/out: temporary memory heap */
+ const rec_t* rec, /*!< in: SYS_INDEXES record */
+ ibool cached, /*!< in: TRUE = add to cache
+ FALSE = do not */
+ dict_index_t** index); /*!< out,own: index, or NULL */
+/********************************************************************//**
+Loads an index field definition from a SYS_FIELDS record to
+dict_index_t.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_load_field_low(
+/*================*/
+ byte* index_id, /*!< in/out: index id (8 bytes)
+ an "in" value if index != NULL
+ and "out" if index == NULL */
+ dict_index_t* index, /*!< in/out: index, could be NULL
+ if we just populate a dict_field_t
+ struct with information from
+ a SYS_FIELDS record */
+ dict_field_t* sys_field, /*!< out: dict_field_t to be
+ filled */
+ ulint* pos, /*!< out: Field position */
+ byte* last_index_id, /*!< in: last index id */
+ mem_heap_t* heap, /*!< in/out: memory heap
+ for temporary storage */
+ const rec_t* rec); /*!< in: SYS_FIELDS record */
/********************************************************************//**
Loads a table definition and also all its index definitions, and also
the cluster definition if the table is a member in a cluster. Also loads
@@ -66,8 +163,9 @@ UNIV_INTERN
dict_table_t*
dict_load_table(
/*============*/
- const char* name); /*!< in: table name in the
+ const char* name, /*!< in: table name in the
databasename/tablename format */
+ ibool cached);/*!< in: TRUE=add to cache, FALSE=do not */
/***********************************************************************//**
Loads a table object based on the table id.
@return table; NULL if table does not exist */
@@ -107,7 +205,113 @@ void
dict_print(void);
/*============*/
-
+/********************************************************************//**
+This function opens a system table, and return the first record.
+@return first record of the system table */
+UNIV_INTERN
+const rec_t*
+dict_startscan_system(
+/*==================*/
+ btr_pcur_t* pcur, /*!< out: persistent cursor to
+ the record */
+ mtr_t* mtr, /*!< in: the mini-transaction */
+ dict_system_id_t system_id); /*!< in: which system table to open */
+/********************************************************************//**
+This function get the next system table record as we scan the table.
+@return the record if found, NULL if end of scan. */
+UNIV_INTERN
+const rec_t*
+dict_getnext_system(
+/*================*/
+ btr_pcur_t* pcur, /*!< in/out: persistent cursor
+ to the record */
+ mtr_t* mtr); /*!< in: the mini-transaction */
+/********************************************************************//**
+This function processes one SYS_TABLES record and populate the dict_table_t
+struct for the table. Extracted out of dict_print() to be used by
+both monitor table output and information schema innodb_sys_tables output.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_tables_rec(
+/*========================*/
+ mem_heap_t* heap, /*!< in: temporary memory heap */
+ const rec_t* rec, /*!< in: SYS_TABLES record */
+ dict_table_t** table, /*!< out: dict_table_t to fill */
+ dict_table_info_t status); /*!< in: status bit controls
+ options such as whether we shall
+ look for dict_table_t from cache
+ first */
+/********************************************************************//**
+This function parses a SYS_INDEXES record and populate a dict_index_t
+structure with the information from the record. For detail information
+about SYS_INDEXES fields, please refer to dict_boot() function.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_indexes_rec(
+/*=========================*/
+ mem_heap_t* heap, /*!< in/out: heap memory */
+ const rec_t* rec, /*!< in: current SYS_INDEXES rec */
+ dict_index_t* index, /*!< out: dict_index_t to be
+ filled */
+ dulint* table_id); /*!< out: table id */
+/********************************************************************//**
+This function parses a SYS_COLUMNS record and populate a dict_column_t
+structure with the information from the record.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_columns_rec(
+/*=========================*/
+ mem_heap_t* heap, /*!< in/out: heap memory */
+ const rec_t* rec, /*!< in: current SYS_COLUMNS rec */
+ dict_col_t* column, /*!< out: dict_col_t to be filled */
+ dulint* table_id, /*!< out: table id */
+ const char** col_name); /*!< out: column name */
+/********************************************************************//**
+This function parses a SYS_FIELDS record and populate a dict_field_t
+structure with the information from the record.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_fields_rec(
+/*========================*/
+ mem_heap_t* heap, /*!< in/out: heap memory */
+ const rec_t* rec, /*!< in: current SYS_FIELDS rec */
+ dict_field_t* sys_field, /*!< out: dict_field_t to be
+ filled */
+ ulint* pos, /*!< out: Field position */
+ dulint* index_id, /*!< out: current index id */
+ dulint last_id); /*!< in: previous index id */
+/********************************************************************//**
+This function parses a SYS_FOREIGN record and populate a dict_foreign_t
+structure with the information from the record. For detail information
+about SYS_FOREIGN fields, please refer to dict_load_foreign() function
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_foreign_rec(
+/*=========================*/
+ mem_heap_t* heap, /*!< in/out: heap memory */
+ const rec_t* rec, /*!< in: current SYS_FOREIGN rec */
+ dict_foreign_t* foreign); /*!< out: dict_foreign_t to be
+ filled */
+/********************************************************************//**
+This function parses a SYS_FOREIGN_COLS record and extract necessary
+information from the record and return to caller.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_foreign_col_rec(
+/*=============================*/
+ mem_heap_t* heap, /*!< in/out: heap memory */
+ const rec_t* rec, /*!< in: current SYS_FOREIGN_COLS rec */
+ const char** name, /*!< out: foreign key constraint name */
+ const char** for_col_name, /*!< out: referencing column name */
+ const char** ref_col_name, /*!< out: referenced column name
+ in referenced table */
+ ulint* pos); /*!< out: column position */
#ifndef UNIV_NONINL
#include "dict0load.ic"
#endif
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index e63fe920daa..f93b2f8c8a3 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -147,6 +147,36 @@ dict_mem_table_add_col(
ulint prtype, /*!< in: precise type */
ulint len); /*!< in: precision */
/**********************************************************************//**
+This function poplulates a dict_col_t memory structure with
+supplied information. */
+UNIV_INLINE
+void
+dict_mem_fill_column_struct(
+/*========================*/
+ dict_col_t* column, /*!< out: column struct to be
+ filled */
+ ulint col_pos, /*!< in: column position */
+ ulint mtype, /*!< in: main data type */
+ ulint prtype, /*!< in: precise type */
+ ulint col_len); /*!< in: column lenght */
+/**********************************************************************//**
+This function poplulates a dict_index_t index memory structure with
+supplied information. */
+UNIV_INLINE
+void
+dict_mem_fill_index_struct(
+/*=======================*/
+ dict_index_t* index, /*!< out: index to be filled */
+ mem_heap_t* heap, /*!< in: memory heap */
+ const char* table_name, /*!< in: table name */
+ const char* index_name, /*!< in: index name */
+ ulint space, /*!< in: space where the index tree is
+ placed, ignored if the index is of
+ the clustered type */
+ ulint type, /*!< in: DICT_UNIQUE,
+ DICT_CLUSTERED, ... ORed */
+ ulint n_fields); /*!< in: number of fields */
+/**********************************************************************//**
Creates an index memory object.
@return own: index object */
UNIV_INTERN
diff --git a/storage/innobase/include/dict0mem.ic b/storage/innobase/include/dict0mem.ic
index c36adb07a18..5a851da5640 100644
--- a/storage/innobase/include/dict0mem.ic
+++ b/storage/innobase/include/dict0mem.ic
@@ -23,4 +23,82 @@ Data dictionary memory object creation
Created 1/8/1996 Heikki Tuuri
***********************************************************************/
+#include "data0type.h"
+#include "dict0mem.h"
+#include "fil0fil.h"
+/**********************************************************************//**
+This function poplulates a dict_index_t index memory structure with
+supplied information. */
+UNIV_INLINE
+void
+dict_mem_fill_index_struct(
+/*=======================*/
+ dict_index_t* index, /*!< out: index to be filled */
+ mem_heap_t* heap, /*!< in: memory heap */
+ const char* table_name, /*!< in: table name */
+ const char* index_name, /*!< in: index name */
+ ulint space, /*!< in: space where the index tree is
+ placed, ignored if the index is of
+ the clustered type */
+ ulint type, /*!< in: DICT_UNIQUE,
+ DICT_CLUSTERED, ... ORed */
+ ulint n_fields) /*!< in: number of fields */
+{
+
+ if (heap) {
+ index->heap = heap;
+ index->name = mem_heap_strdup(heap, index_name);
+ index->fields = (dict_field_t*) mem_heap_alloc(
+ heap, 1 + n_fields * sizeof(dict_field_t));
+ } else {
+ index->name = index_name;
+ index->heap = NULL;
+ index->fields = NULL;
+ }
+
+ index->type = type;
+#ifndef UNIV_HOTBACKUP
+ index->space = (unsigned int) space;
+ index->page = FIL_NULL;
+#endif /* !UNIV_HOTBACKUP */
+ index->table_name = table_name;
+ index->n_fields = (unsigned int) n_fields;
+ /* The '1 +' above prevents allocation
+ of an empty mem block */
+#ifdef UNIV_DEBUG
+ index->magic_n = DICT_INDEX_MAGIC_N;
+#endif /* UNIV_DEBUG */
+}
+
+/**********************************************************************//**
+This function poplulates a dict_col_t memory structure with
+supplied information. */
+UNIV_INLINE
+void
+dict_mem_fill_column_struct(
+/*========================*/
+ dict_col_t* column, /*!< out: column struct to be
+ filled */
+ ulint col_pos, /*!< in: column position */
+ ulint mtype, /*!< in: main data type */
+ ulint prtype, /*!< in: precise type */
+ ulint col_len) /*!< in: column lenght */
+{
+#ifndef UNIV_HOTBACKUP
+ ulint mbminlen;
+ ulint mbmaxlen;
+#endif /* !UNIV_HOTBACKUP */
+
+ column->ind = (unsigned int) col_pos;
+ column->ord_part = 0;
+ column->mtype = (unsigned int) mtype;
+ column->prtype = (unsigned int) prtype;
+ column->len = (unsigned int) col_len;
+#ifndef UNIV_HOTBACKUP
+ dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen);
+
+ column->mbminlen = (unsigned int) mbminlen;
+ column->mbmaxlen = (unsigned int) mbmaxlen;
+#endif /* !UNIV_HOTBACKUP */
+}
diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
index a98dd8d2900..cc2bd415163 100644
--- a/storage/innobase/row/row0mysql.c
+++ b/storage/innobase/row/row0mysql.c
@@ -3285,7 +3285,7 @@ check_next_foreign:
dict_table_remove_from_cache(table);
- if (dict_load_table(name) != NULL) {
+ if (dict_load_table(name, TRUE) != NULL) {
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: not able to remove table ",
stderr);
@@ -3431,7 +3431,7 @@ row_mysql_drop_temp_tables(void)
btr_pcur_store_position(&pcur, &mtr);
btr_pcur_commit_specify_mtr(&pcur, &mtr);
- table = dict_load_table(table_name);
+ table = dict_load_table(table_name, TRUE);
if (table) {
row_drop_table_for_mysql(table_name, trx, FALSE);