diff options
author | Jimmy Yang <jimmy.yang@oracle.com> | 2010-05-25 18:44:33 -0700 |
---|---|---|
committer | Jimmy Yang <jimmy.yang@oracle.com> | 2010-05-25 18:44:33 -0700 |
commit | 00dfb12b9221ec1b2b84d9ddd1309e0b440fc889 (patch) | |
tree | 54d2fd9cdef475dd2487f9d00495e5580c93e63d /storage | |
parent | 7d50be10d2d5f9cff913b386ac0f1473971b993e (diff) | |
download | mariadb-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.c | 1249 | ||||
-rw-r--r-- | storage/innobase/dict/dict0mem.c | 35 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 10 | ||||
-rw-r--r-- | storage/innobase/handler/i_s.cc | 1667 | ||||
-rw-r--r-- | storage/innobase/handler/i_s.h | 7 | ||||
-rw-r--r-- | storage/innobase/include/dict0dict.ic | 2 | ||||
-rw-r--r-- | storage/innobase/include/dict0load.h | 208 | ||||
-rw-r--r-- | storage/innobase/include/dict0mem.h | 30 | ||||
-rw-r--r-- | storage/innobase/include/dict0mem.ic | 78 | ||||
-rw-r--r-- | storage/innobase/row/row0mysql.c | 4 |
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); |