Commit 60d42882 authored by Jimmy Yang's avatar Jimmy Yang

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
parent a80c59c7
...@@ -109,13 +109,20 @@ Database: information_schema ...@@ -109,13 +109,20 @@ Database: information_schema
| TRIGGERS | | TRIGGERS |
| USER_PRIVILEGES | | USER_PRIVILEGES |
| VIEWS | | VIEWS |
| INNODB_CMP_RESET | | INNODB_SYS_FIELDS |
| INNODB_TRX | | INNODB_TRX |
| INNODB_CMPMEM_RESET | | INNODB_SYS_INDEXES |
| INNODB_LOCK_WAITS | | INNODB_LOCK_WAITS |
| INNODB_CMPMEM | | INNODB_SYS_TABLESTATS |
| INNODB_CMP | | INNODB_CMP |
| INNODB_SYS_COLUMNS |
| INNODB_CMP_RESET |
| INNODB_SYS_FOREIGN_COLS |
| INNODB_LOCKS | | INNODB_LOCKS |
| INNODB_CMPMEM_RESET |
| INNODB_CMPMEM |
| INNODB_SYS_FOREIGN |
| INNODB_SYS_TABLES |
+---------------------------------------+ +---------------------------------------+
Database: INFORMATION_SCHEMA Database: INFORMATION_SCHEMA
+---------------------------------------+ +---------------------------------------+
...@@ -151,13 +158,20 @@ Database: INFORMATION_SCHEMA ...@@ -151,13 +158,20 @@ Database: INFORMATION_SCHEMA
| TRIGGERS | | TRIGGERS |
| USER_PRIVILEGES | | USER_PRIVILEGES |
| VIEWS | | VIEWS |
| INNODB_CMP_RESET | | INNODB_SYS_FIELDS |
| INNODB_TRX | | INNODB_TRX |
| INNODB_CMPMEM_RESET | | INNODB_SYS_INDEXES |
| INNODB_LOCK_WAITS | | INNODB_LOCK_WAITS |
| INNODB_CMPMEM | | INNODB_SYS_TABLESTATS |
| INNODB_CMP | | INNODB_CMP |
| INNODB_SYS_COLUMNS |
| INNODB_CMP_RESET |
| INNODB_SYS_FOREIGN_COLS |
| INNODB_LOCKS | | INNODB_LOCKS |
| INNODB_CMPMEM_RESET |
| INNODB_CMPMEM |
| INNODB_SYS_FOREIGN |
| INNODB_SYS_TABLES |
+---------------------------------------+ +---------------------------------------+
Wildcard: inf_rmation_schema Wildcard: inf_rmation_schema
+--------------------+ +--------------------+
......
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES;
TABLE_ID NAME FLAG N_COLS SPACE
11 SYS_FOREIGN 0 7 0
12 SYS_FOREIGN_COLS 0 7 0
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES;
INDEX_ID NAME TABLE_ID TYPE N_FIELDS PAGE_NO SPACE
11 ID_IND 11 3 1 302 0
12 FOR_IND 11 0 1 303 0
13 REF_IND 11 0 1 304 0
14 ID_IND 12 3 2 305 0
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS;
TABLE_ID NAME POS MTYPE PRTYPE LEN
11 ID 0 1 524292 0
11 FOR_NAME 1 1 524292 0
11 REF_NAME 2 1 524292 0
11 N_COLS 3 6 0 4
12 ID 0 1 524292 0
12 POS 1 6 0 4
12 FOR_COL_NAME 2 1 524292 0
12 REF_COL_NAME 3 1 524292 0
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FIELDS;
INDEX_ID NAME POS
11 ID 0
12 FOR_NAME 0
13 REF_NAME 0
14 ID 0
14 POS 1
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
ID FOR_NAME REF_NAME N_COLS TYPE
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
ID FOR_COL_NAME REF_COL_NAME POS
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS;
TABLE_ID NAME STATS_INITIALIZED NUM_ROWS CLUST_INDEX_SIZE OTHER_INDEX_SIZE MODIFIED_COUNTER AUTOINC MYSQL_HANDLES_OPENED
11 SYS_FOREIGN Uninitialized 0 0 0 0 0 0
12 SYS_FOREIGN_COLS Uninitialized 0 0 0 0 0 0
CREATE TABLE parent (id INT NOT NULL,
PRIMARY KEY (id)) ENGINE=INNODB;
CREATE TABLE child (id INT, parent_id INT,
INDEX par_ind (parent_id),
CONSTRAINT constraint_test
FOREIGN KEY (parent_id) REFERENCES parent(id)
ON DELETE CASCADE) ENGINE=INNODB;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
ID FOR_NAME REF_NAME N_COLS TYPE
test/constraint_test test/child test/parent 1 1
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
ID FOR_COL_NAME REF_COL_NAME POS
test/constraint_test parent_id id 0
INSERT INTO parent VALUES(1);
SELECT name, num_rows, mysql_handles_opened
FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS
WHERE name LIKE "%parent";
name num_rows mysql_handles_opened
test/parent 1 1
SELECT NAME, FLAG, N_COLS, SPACE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES;
NAME FLAG N_COLS SPACE
SYS_FOREIGN 0 7 0
SYS_FOREIGN_COLS 0 7 0
test/child 1 5 0
test/parent 1 4 0
SELECT name, n_fields
from INFORMATION_SCHEMA.INNODB_SYS_INDEXES
WHERE table_id In (SELECT table_id from
INFORMATION_SCHEMA.INNODB_SYS_TABLES
WHERE name LIKE "%parent%");
name n_fields
PRIMARY 1
SELECT name, n_fields
from INFORMATION_SCHEMA.INNODB_SYS_INDEXES
WHERE table_id In (SELECT table_id from
INFORMATION_SCHEMA.INNODB_SYS_TABLES
WHERE name LIKE "%child%");
name n_fields
GEN_CLUST_INDEX 0
par_ind 1
SELECT name, pos, mtype, len
from INFORMATION_SCHEMA.INNODB_SYS_COLUMNS
WHERE table_id In (SELECT table_id from
INFORMATION_SCHEMA.INNODB_SYS_TABLES
WHERE name LIKE "%child%");
name pos mtype len
id 0 6 4
parent_id 1 6 4
DROP TABLE child;
DROP TABLE parent;
CREATE TABLE parent (id INT NOT NULL, newid INT NOT NULL,
PRIMARY KEY (id, newid)) ENGINE=INNODB;
CREATE TABLE child (id INT, parent_id INT,
INDEX par_ind (parent_id),
CONSTRAINT constraint_test
FOREIGN KEY (id, parent_id) REFERENCES parent(id, newid)
ON DELETE CASCADE) ENGINE=INNODB;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
ID FOR_NAME REF_NAME N_COLS TYPE
test/constraint_test test/child test/parent 2 1
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
ID FOR_COL_NAME REF_COL_NAME POS
test/constraint_test id id 0
test/constraint_test parent_id newid 1
INSERT INTO parent VALUES(1, 9);
SELECT * FROM parent WHERE id IN (SELECT id FROM parent);
id newid
1 9
SELECT name, num_rows, mysql_handles_opened
FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS
WHERE name LIKE "%parent";
name num_rows mysql_handles_opened
test/parent 1 2
DROP TABLE child;
DROP TABLE parent;
# This is the test for Information Schema System Table View
# that displays the InnoDB system table content through
# information schema tables.
--source include/have_innodb.inc
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FIELDS;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS;
# Create a foreign key constraint, and verify the information
# in INFORMATION_SCHEMA.INNODB_SYS_FOREIGN and
# INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS
CREATE TABLE parent (id INT NOT NULL,
PRIMARY KEY (id)) ENGINE=INNODB;
CREATE TABLE child (id INT, parent_id INT,
INDEX par_ind (parent_id),
CONSTRAINT constraint_test
FOREIGN KEY (parent_id) REFERENCES parent(id)
ON DELETE CASCADE) ENGINE=INNODB;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
# Insert a row in the table "parent", and see whether that reflected in
# INNODB_SYS_TABLESTATS
INSERT INTO parent VALUES(1);
SELECT name, num_rows, mysql_handles_opened
FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS
WHERE name LIKE "%parent";
SELECT NAME, FLAG, N_COLS, SPACE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES;
SELECT name, n_fields
from INFORMATION_SCHEMA.INNODB_SYS_INDEXES
WHERE table_id In (SELECT table_id from
INFORMATION_SCHEMA.INNODB_SYS_TABLES
WHERE name LIKE "%parent%");
SELECT name, n_fields
from INFORMATION_SCHEMA.INNODB_SYS_INDEXES
WHERE table_id In (SELECT table_id from
INFORMATION_SCHEMA.INNODB_SYS_TABLES
WHERE name LIKE "%child%");
SELECT name, pos, mtype, len
from INFORMATION_SCHEMA.INNODB_SYS_COLUMNS
WHERE table_id In (SELECT table_id from
INFORMATION_SCHEMA.INNODB_SYS_TABLES
WHERE name LIKE "%child%");
DROP TABLE child;
DROP TABLE parent;
# Create table with 2 columns in the foreign key constraint
CREATE TABLE parent (id INT NOT NULL, newid INT NOT NULL,
PRIMARY KEY (id, newid)) ENGINE=INNODB;
CREATE TABLE child (id INT, parent_id INT,
INDEX par_ind (parent_id),
CONSTRAINT constraint_test
FOREIGN KEY (id, parent_id) REFERENCES parent(id, newid)
ON DELETE CASCADE) ENGINE=INNODB;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
INSERT INTO parent VALUES(1, 9);
# Nested query will open the table handle twice
SELECT * FROM parent WHERE id IN (SELECT id FROM parent);
SELECT name, num_rows, mysql_handles_opened
FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS
WHERE name LIKE "%parent";
DROP TABLE child;
DROP TABLE parent;
...@@ -41,6 +41,16 @@ Created 4/24/1996 Heikki Tuuri ...@@ -41,6 +41,16 @@ Created 4/24/1996 Heikki Tuuri
#include "srv0start.h" #include "srv0start.h"
#include "srv0srv.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. Compare the name of an index column.
@return TRUE if the i'th column of index is 'name'. */ @return TRUE if the i'th column of index is 'name'. */
...@@ -151,13 +161,10 @@ void ...@@ -151,13 +161,10 @@ void
dict_print(void) dict_print(void)
/*============*/ /*============*/
{ {
dict_table_t* sys_tables;
dict_index_t* sys_index;
dict_table_t* table; dict_table_t* table;
btr_pcur_t pcur; btr_pcur_t pcur;
const rec_t* rec; const rec_t* rec;
const byte* field; mem_heap_t* heap;
ulint len;
mtr_t mtr; mtr_t mtr;
/* Enlarge the fatal semaphore wait timeout during the InnoDB table /* Enlarge the fatal semaphore wait timeout during the InnoDB table
...@@ -167,75 +174,396 @@ dict_print(void) ...@@ -167,75 +174,396 @@ dict_print(void)
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */ srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
heap = mem_heap_create(1000);
mutex_enter(&(dict_sys->mutex)); mutex_enter(&(dict_sys->mutex));
mtr_start(&mtr); mtr_start(&mtr);
sys_tables = dict_table_get_low("SYS_TABLES"); rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
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);
rec = btr_pcur_get_rec(&pcur); while (rec) {
const char* err_msg;
if (!btr_pcur_is_on_user_rec(&pcur)) { err_msg = dict_process_sys_tables_rec(
/* end of index */ heap, rec, &table, DICT_TABLE_LOAD_FROM_CACHE
| DICT_TABLE_UPDATE_STATS);
btr_pcur_close(&pcur);
mtr_commit(&mtr); 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);
}
/* Restore the fatal semaphore wait timeout */ mem_heap_empty(heap);
mutex_enter(&kernel_mutex); mtr_start(&mtr);
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */ rec = dict_getnext_system(&pcur, &mtr);
mutex_exit(&kernel_mutex); }
return; mtr_commit(&mtr);
mutex_exit(&(dict_sys->mutex));
mem_heap_free(heap);
/* 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); btr_pcur_open_at_index_side(TRUE, clust_index, BTR_SEARCH_LEAF, pcur,
mem_free(table_name); TRUE, mtr);
if (table == NULL) { rec = dict_getnext_system_low(pcur, mtr);
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 */
if (dict_table_get_first_index(table)) { return(rec);
dict_update_statistics_low(table, TRUE); }
}
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. Determine the flags of a table described in SYS_TABLES.
@return compressed page size in kilobytes; or 0 if the tablespace is @return compressed page size in kilobytes; or 0 if the tablespace is
...@@ -441,130 +769,156 @@ dict_check_tablespaces_and_store_max_id( ...@@ -441,130 +769,156 @@ dict_check_tablespaces_and_store_max_id(
} }
/********************************************************************//** /********************************************************************//**
Loads definitions for table columns. */ Loads a table column definition from a SYS_COLUMNS record to
static dict_table_t.
void @return error message, or NULL on success */
dict_load_columns( UNIV_INTERN
/*==============*/ const char*
dict_table_t* table, /*!< in: table */ dict_load_column_low(
mem_heap_t* heap) /*!< in: memory heap for temporary storage */ /*=================*/
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 */
{ {
dict_table_t* sys_columns; char* name;
dict_index_t* sys_index;
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
const rec_t* rec;
const byte* field; const byte* field;
ulint len; ulint len;
byte* buf;
char* name;
ulint mtype; ulint mtype;
ulint prtype; ulint prtype;
ulint col_len; ulint col_len;
ulint i; ulint pos;
mtr_t mtr;
ut_ad(mutex_own(&(dict_sys->mutex)));
mtr_start(&mtr);
sys_columns = dict_table_get_low("SYS_COLUMNS"); if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
sys_index = UT_LIST_GET_FIRST(sys_columns->indexes); return("delete-marked record in SYS_COLUMNS");
ut_a(!dict_table_is_comp(sys_columns)); }
tuple = dtuple_create(heap, 1); if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) {
dfield = dtuple_get_nth_field(tuple, 0); return("wrong number of columns in SYS_COLUMNS record");
}
buf = mem_heap_alloc(heap, 8); field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len);
mach_write_to_8(buf, table->id); if (UNIV_UNLIKELY(len != 8)) {
err_len:
return("incorrect column length in SYS_COLUMNS");
}
dfield_set_data(dfield, buf, 8); if (table_id) {
dict_index_copy_types(tuple, sys_index, 1); *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");
}
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
BTR_SEARCH_LEAF, &pcur, &mtr); if (UNIV_UNLIKELY(len != 4)) {
for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
rec = btr_pcur_get_rec(&pcur); goto err_len;
}
ut_a(btr_pcur_is_on_user_rec(&pcur)); 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");
}
ut_a(!rec_get_deleted_flag(rec, 0)); 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, 0, &len); field = rec_get_nth_field_old(rec, 4/*NAME*/, &len);
ut_ad(len == 8); if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
ut_a(ut_dulint_cmp(table->id, mach_read_from_8(field)) == 0); goto err_len;
}
field = rec_get_nth_field_old(rec, 1, &len); name = mem_heap_strdupl(heap, (const char*) field, len);
ut_ad(len == 4);
ut_a(i == mach_read_from_4(field));
ut_a(name_of_col_is(sys_columns, sys_index, 4, "NAME")); if (col_name) {
*col_name = name;
}
field = rec_get_nth_field_old(rec, 4, &len); field = rec_get_nth_field_old(rec, 5/*MTYPE*/, &len);
name = mem_heap_strdupl(heap, (char*) field, len); if (UNIV_UNLIKELY(len != 4)) {
goto err_len;
}
field = rec_get_nth_field_old(rec, 5, &len); mtype = mach_read_from_4(field);
mtype = mach_read_from_4(field);
field = rec_get_nth_field_old(rec, 6, &len); field = rec_get_nth_field_old(rec, 6/*PRTYPE*/, &len);
prtype = mach_read_from_4(field); if (UNIV_UNLIKELY(len != 4)) {
goto err_len;
}
prtype = mach_read_from_4(field);
if (dtype_get_charset_coll(prtype) == 0 if (dtype_get_charset_coll(prtype) == 0
&& dtype_is_string_type(mtype)) { && dtype_is_string_type(mtype)) {
/* The table was created with < 4.1.2. */ /* The table was created with < 4.1.2. */
if (dtype_is_binary_string_type(mtype, prtype)) { if (dtype_is_binary_string_type(mtype, prtype)) {
/* Use the binary collation for /* Use the binary collation for
string columns of binary type. */ string columns of binary type. */
prtype = dtype_form_prtype( prtype = dtype_form_prtype(
prtype, prtype,
DATA_MYSQL_BINARY_CHARSET_COLL); DATA_MYSQL_BINARY_CHARSET_COLL);
} else { } else {
/* Use the default charset for /* Use the default charset for
other than binary columns. */ other than binary columns. */
prtype = dtype_form_prtype( prtype = dtype_form_prtype(
prtype, prtype,
data_mysql_default_charset_coll); data_mysql_default_charset_coll);
}
} }
}
field = rec_get_nth_field_old(rec, 7, &len); field = rec_get_nth_field_old(rec, 7/*LEN*/, &len);
col_len = mach_read_from_4(field); if (UNIV_UNLIKELY(len != 4)) {
goto err_len;
ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC")); }
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;
}
dict_mem_table_add_col(table, heap, name, if (!column) {
mtype, prtype, col_len); dict_mem_table_add_col(table, heap, name, mtype,
btr_pcur_move_to_next_user_rec(&pcur, &mtr); prtype, col_len);
} else {
dict_mem_fill_column_struct(column, pos, mtype,
prtype, col_len);
} }
btr_pcur_close(&pcur); return(NULL);
mtr_commit(&mtr);
} }
/********************************************************************//** /********************************************************************//**
Loads definitions for index fields. */ Loads definitions for table columns. */
static static
void void
dict_load_fields( dict_load_columns(
/*=============*/ /*==============*/
dict_index_t* index, /*!< in: index whose fields to load */ dict_table_t* table, /*!< in/out: table */
mem_heap_t* heap) /*!< in: memory heap for temporary storage */ mem_heap_t* heap) /*!< in/out: memory heap
for temporary storage */
{ {
dict_table_t* sys_fields; dict_table_t* sys_columns;
dict_index_t* sys_index; dict_index_t* sys_index;
btr_pcur_t pcur; btr_pcur_t pcur;
dtuple_t* tuple; dtuple_t* tuple;
dfield_t* dfield; dfield_t* dfield;
ulint pos_and_prefix_len;
ulint prefix_len;
const rec_t* rec; const rec_t* rec;
const byte* field;
ulint len;
byte* buf; byte* buf;
ulint i; ulint i;
mtr_t mtr; mtr_t mtr;
...@@ -573,78 +927,356 @@ dict_load_fields( ...@@ -573,78 +927,356 @@ dict_load_fields(
mtr_start(&mtr); mtr_start(&mtr);
sys_fields = dict_table_get_low("SYS_FIELDS"); sys_columns = dict_table_get_low("SYS_COLUMNS");
sys_index = UT_LIST_GET_FIRST(sys_fields->indexes); sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
ut_a(!dict_table_is_comp(sys_fields)); 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); tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0); dfield = dtuple_get_nth_field(tuple, 0);
buf = mem_heap_alloc(heap, 8); buf = mem_heap_alloc(heap, 8);
mach_write_to_8(buf, index->id); mach_write_to_8(buf, table->id);
dfield_set_data(dfield, buf, 8); dfield_set_data(dfield, buf, 8);
dict_index_copy_types(tuple, sys_index, 1); dict_index_copy_types(tuple, sys_index, 1);
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr); BTR_SEARCH_LEAF, &pcur, &mtr);
for (i = 0; i < index->n_fields; i++) { for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
const char* err_msg;
rec = btr_pcur_get_rec(&pcur); rec = btr_pcur_get_rec(&pcur);
ut_a(btr_pcur_is_on_user_rec(&pcur)); ut_a(btr_pcur_is_on_user_rec(&pcur));
/* There could be delete marked records in SYS_FIELDS err_msg = dict_load_column_low(table, heap, NULL, NULL,
because SYS_FIELDS.INDEX_ID can be updated NULL, rec);
by ALTER TABLE ADD INDEX. */
if (rec_get_deleted_flag(rec, 0)) { if (err_msg) {
fprintf(stderr, "InnoDB: %s\n", err_msg);
goto next_rec; ut_error;
} }
field = rec_get_nth_field_old(rec, 0, &len); btr_pcur_move_to_next_user_rec(&pcur, &mtr);
ut_ad(len == 8); }
field = rec_get_nth_field_old(rec, 1, &len);
ut_a(len == 4);
/* The next field stores the field position in the index btr_pcur_close(&pcur);
and a possible column prefix length if the index field mtr_commit(&mtr);
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. */
pos_and_prefix_len = mach_read_from_4(field); /** 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";
ut_a((pos_and_prefix_len & 0xFFFFUL) == i /********************************************************************//**
|| (pos_and_prefix_len & 0xFFFF0000UL) == (i << 16)); 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;
if ((i == 0 && pos_and_prefix_len > 0) /* Either index or sys_field is supplied, not both */
|| (pos_and_prefix_len & 0xFFFF0000UL) > 0) { ut_a((!index) || (!sys_field));
prefix_len = pos_and_prefix_len & 0xFFFFUL; if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
} else { return(dict_load_field_del);
prefix_len = 0; }
if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 5)) {
return("wrong number of columns in SYS_FIELDS record");
}
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");
}
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");
} }
}
ut_a(name_of_col_is(sys_fields, sys_index, 4, "COL_NAME")); field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
if (UNIV_UNLIKELY(len != 4)) {
goto err_len;
}
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;
}
/* 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");
}
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.
@return DB_SUCCESS if ok, DB_CORRUPTION if corruption */
static
ulint
dict_load_fields(
/*=============*/
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;
dict_index_t* sys_index;
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
const rec_t* rec;
byte* buf;
ulint i;
mtr_t mtr;
ulint error;
ut_ad(mutex_own(&(dict_sys->mutex)));
mtr_start(&mtr);
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);
buf = mem_heap_alloc(heap, 8);
mach_write_to_8(buf, index->id);
dfield_set_data(dfield, buf, 8);
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);
for (i = 0; i < index->n_fields; i++) {
const char* err_msg;
dict_mem_index_add_field(index, rec = btr_pcur_get_rec(&pcur);
mem_heap_strdupl(heap,
(char*) field, len), ut_a(btr_pcur_is_on_user_rec(&pcur));
prefix_len);
err_msg = dict_load_field_low(buf, index, NULL, NULL, NULL,
heap, rec);
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: next_rec:
btr_pcur_move_to_next_user_rec(&pcur, &mtr); btr_pcur_move_to_next_user_rec(&pcur, &mtr);
} }
error = DB_SUCCESS;
func_exit:
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
mtr_commit(&mtr); mtr_commit(&mtr);
return(error);
}
/** 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";
/********************************************************************//**
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);
}
if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) {
return("wrong number of columns in SYS_INDEXES 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_INDEXES");
}
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);
}
field = rec_get_nth_field_old(rec, 1/*ID*/, &len);
if (UNIV_UNLIKELY(len != 8)) {
goto err_len;
}
id = mach_read_from_8(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/*NAME*/, &name_len);
if (UNIV_UNLIKELY(name_len == UNIV_SQL_NULL)) {
goto err_len;
}
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);
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 ...@@ -656,27 +1288,17 @@ static
ulint ulint
dict_load_indexes( 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 */ mem_heap_t* heap) /*!< in: memory heap for temporary storage */
{ {
dict_table_t* sys_indexes; dict_table_t* sys_indexes;
dict_index_t* sys_index; dict_index_t* sys_index;
dict_index_t* index;
btr_pcur_t pcur; btr_pcur_t pcur;
dtuple_t* tuple; dtuple_t* tuple;
dfield_t* dfield; dfield_t* dfield;
const rec_t* rec; 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; byte* buf;
ibool is_sys_table; ibool is_sys_table;
dulint id;
mtr_t mtr; mtr_t mtr;
ulint error = DB_SUCCESS; ulint error = DB_SUCCESS;
...@@ -694,6 +1316,8 @@ dict_load_indexes( ...@@ -694,6 +1316,8 @@ dict_load_indexes(
sys_indexes = dict_table_get_low("SYS_INDEXES"); sys_indexes = dict_table_get_low("SYS_INDEXES");
sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes); sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);
ut_a(!dict_table_is_comp(sys_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); tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0); dfield = dtuple_get_nth_field(tuple, 0);
...@@ -707,6 +1331,9 @@ dict_load_indexes( ...@@ -707,6 +1331,9 @@ dict_load_indexes(
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr); BTR_SEARCH_LEAF, &pcur, &mtr);
for (;;) { for (;;) {
dict_index_t* index;
const char* err_msg;
if (!btr_pcur_is_on_user_rec(&pcur)) { if (!btr_pcur_is_on_user_rec(&pcur)) {
break; break;
...@@ -714,90 +1341,73 @@ dict_load_indexes( ...@@ -714,90 +1341,73 @@ dict_load_indexes(
rec = btr_pcur_get_rec(&pcur); rec = btr_pcur_get_rec(&pcur);
field = rec_get_nth_field_old(rec, 0, &len); err_msg = dict_load_index_low(buf, table->name, heap, rec,
ut_ad(len == 8); 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; break;
} else if (rec_get_deleted_flag(rec, 0)) { } else if (err_msg == dict_load_index_del) {
/* Skip delete marked records */ /* Skip delete-marked records. */
goto next_rec; 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(index);
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);
/* We check for unsupported types first, so that the /* We check for unsupported types first, so that the
subsequent checks are relevant for the supported types. */ subsequent checks are relevant for the supported types. */
if (type & ~(DICT_CLUSTERED | DICT_UNIQUE)) { if (index->type & ~(DICT_CLUSTERED | DICT_UNIQUE)) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Error: unknown type %lu" "InnoDB: Error: unknown type %lu"
" of index %s of table %s\n", " of index %s of table %s\n",
(ulong) type, name_buf, table->name); (ulong) index->type, index->name, table->name);
error = DB_UNSUPPORTED; error = DB_UNSUPPORTED;
dict_mem_index_free(index);
goto func_exit; goto func_exit;
} else if (page_no == FIL_NULL) { } else if (index->page == FIL_NULL) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Error: trying to load index %s" "InnoDB: Error: trying to load index %s"
" for table %s\n" " for table %s\n"
"InnoDB: but the index tree has been freed!\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; error = DB_CORRUPTION;
goto func_exit; goto func_exit;
} else if ((type & DICT_CLUSTERED) == 0 } else if (!dict_index_is_clust(index)
&& NULL == dict_table_get_first_index(table)) { && NULL == dict_table_get_first_index(table)) {
fputs("InnoDB: Error: trying to load index ", fputs("InnoDB: Error: trying to load index ",
stderr); stderr);
ut_print_name(stderr, NULL, FALSE, name_buf); ut_print_name(stderr, NULL, FALSE, index->name);
fputs(" for table ", stderr); fputs(" for table ", stderr);
ut_print_name(stderr, NULL, TRUE, table->name); ut_print_name(stderr, NULL, TRUE, table->name);
fputs("\nInnoDB: but the first index" fputs("\nInnoDB: but the first index"
" is not clustered!\n", stderr); " is not clustered!\n", stderr);
error = DB_CORRUPTION; goto corrupted;
goto func_exit;
} else if (is_sys_table } else if (is_sys_table
&& ((type & DICT_CLUSTERED) && (dict_index_is_clust(index)
|| ((table == dict_sys->sys_tables) || ((table == dict_sys->sys_tables)
&& (name_len == (sizeof "ID_IND") - 1) && !strcmp("ID_IND", index->name)))) {
&& (0 == ut_memcmp(name_buf,
"ID_IND", name_len))))) {
/* The index was created in memory already at booting /* The index was created in memory already at booting
of the database server */ of the database server */
dict_mem_index_free(index);
} else { } else {
index = dict_mem_index_create(table->name, name_buf,
space, type, n_fields);
index->id = id;
dict_load_fields(index, heap); dict_load_fields(index, heap);
error = dict_index_add_to_cache(table, index, page_no, error = dict_index_add_to_cache(table, index,
FALSE); index->page, FALSE);
/* The data dictionary tables should never contain /* The data dictionary tables should never contain
invalid index definitions. If we ignored this error invalid index definitions. If we ignored this error
and simply did not load this index definition, the and simply did not load this index definition, the
...@@ -821,80 +1431,83 @@ dict_load_indexes( ...@@ -821,80 +1431,83 @@ dict_load_indexes(
} }
/********************************************************************//** /********************************************************************//**
Loads a table definition and also all its index definitions, and also Loads a table definition from a SYS_TABLES record to dict_table_t.
the cluster definition if the table is a member in a cluster. Also loads Does not load any columns or indexes.
all foreign key constraints where the foreign key is in the table or where @return error message, or NULL on success */
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 UNIV_INTERN
dict_table_t* const char*
dict_load_table( dict_load_table_low(
/*============*/ /*================*/
const char* name) /*!< in: table name in the const char* name, /*!< in: table name */
databasename/tablename format */ 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; const byte* field;
ulint len; ulint len;
ulint space; ulint space;
ulint n_cols; ulint n_cols;
ulint flags; 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"); rec_get_nth_field_offs_old(rec, 3/*ID*/, &len);
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); if (UNIV_UNLIKELY(len != 8)) {
ut_a(!dict_table_is_comp(sys_tables)); goto err_len;
}
tuple = dtuple_create(heap, 1); field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
dfield = dtuple_get_nth_field(tuple, 0); if (UNIV_UNLIKELY(len != 4)) {
goto err_len;
}
dfield_set_data(dfield, name, ut_strlen(name)); n_cols = mach_read_from_4(field);
dict_index_copy_types(tuple, sys_index, 1);
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, rec_get_nth_field_offs_old(rec, 5/*TYPE*/, &len);
BTR_SEARCH_LEAF, &pcur, &mtr); if (UNIV_UNLIKELY(len != 4)) {
rec = btr_pcur_get_rec(&pcur); goto err_len;
}
if (!btr_pcur_is_on_user_rec(&pcur) rec_get_nth_field_offs_old(rec, 6/*MIX_ID*/, &len);
|| rec_get_deleted_flag(rec, 0)) { if (UNIV_UNLIKELY(len != 8)) {
/* Not found */ goto err_len;
err_exit: }
btr_pcur_close(&pcur);
mtr_commit(&mtr);
mem_heap_free(heap);
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 */ field = rec_get_nth_field_old(rec, 9/*SPACE*/, &len);
if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) {
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); space = mach_read_from_4(field);
/* Check if the tablespace exists and has the right name */ /* Check if the tablespace exists and has the right name */
...@@ -902,7 +1515,8 @@ dict_load_table( ...@@ -902,7 +1515,8 @@ dict_load_table(
flags = dict_sys_tables_get_flags(rec); flags = dict_sys_tables_get_flags(rec);
if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) { 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); flags = mach_read_from_4(field);
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
...@@ -912,17 +1526,12 @@ dict_load_table( ...@@ -912,17 +1526,12 @@ dict_load_table(
"InnoDB: in InnoDB data dictionary" "InnoDB: in InnoDB data dictionary"
" has unknown type %lx.\n", " has unknown type %lx.\n",
(ulong) flags); (ulong) flags);
goto err_exit; return(NULL);
} }
} else { } else {
flags = 0; 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. /* The high-order bit of N_COLS is the "compact format" flag.
For tables in that format, MIX_LEN may hold additional flags. */ For tables in that format, MIX_LEN may hold additional flags. */
if (n_cols & 0x80000000UL) { if (n_cols & 0x80000000UL) {
...@@ -930,9 +1539,13 @@ dict_load_table( ...@@ -930,9 +1539,13 @@ dict_load_table(
flags |= DICT_TF_COMPACT; 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); field = rec_get_nth_field_old(rec, 7, &len);
if (UNIV_UNLIKELY(len != 4)) {
goto err_len;
}
flags2 = mach_read_from_4(field); flags2 = mach_read_from_4(field);
if (flags2 & (~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT))) { if (flags2 & (~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT))) {
...@@ -951,53 +1564,145 @@ dict_load_table( ...@@ -951,53 +1564,145 @@ dict_load_table(
} }
/* See if the tablespace is available. */ /* 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. */ /* The system tablespace is always available. */
} else if (!fil_space_for_table_exists_in_mem( } else if (!fil_space_for_table_exists_in_mem(
space, name, table->space, name,
(flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY, (table->flags >> DICT_TF2_SHIFT)
& DICT_TF2_TEMPORARY,
FALSE, FALSE)) { 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. */ /* Do not bother to retry opening temporary tables. */
ibd_file_missing = TRUE; table->ibd_file_missing = TRUE;
} else { } else {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fprintf(stderr,
" InnoDB: error: space object of table"); " InnoDB: error: space object of table ");
ut_print_filename(stderr, name); ut_print_filename(stderr, name);
fprintf(stderr, ",\n" fprintf(stderr, ",\n"
"InnoDB: space id %lu did not exist in memory." "InnoDB: space id %lu did not exist in memory."
" Retrying an open.\n", " Retrying an open.\n",
(ulong) space); (ulong) table->space);
/* Try to open the tablespace */ /* Try to open the tablespace */
if (!fil_open_single_table_tablespace( if (!fil_open_single_table_tablespace(
TRUE, space, TRUE, table->space,
flags & ~(~0 << DICT_TF_BITS), name)) { table->flags & ~(~0 << DICT_TF_BITS), name)) {
/* We failed to find a sensible /* We failed to find a sensible
tablespace file */ 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); btr_pcur_close(&pcur);
mtr_commit(&mtr); mtr_commit(&mtr);
dict_load_columns(table, heap); 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); mem_heap_empty(heap);
...@@ -1007,7 +1712,8 @@ dict_load_table( ...@@ -1007,7 +1712,8 @@ dict_load_table(
of the error condition, since the user may want to dump data from the 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 clustered index. However we load the foreign key information only if
all indexes were loaded. */ all indexes were loaded. */
if (err == DB_SUCCESS) { if (!cached) {
} else if (err == DB_SUCCESS) {
err = dict_load_foreigns(table->name, TRUE); err = dict_load_foreigns(table->name, TRUE);
} else if (!srv_force_recovery) { } else if (!srv_force_recovery) {
dict_table_remove_from_cache(table); dict_table_remove_from_cache(table);
...@@ -1124,7 +1830,8 @@ dict_load_table_on_id( ...@@ -1124,7 +1830,8 @@ dict_load_table_on_id(
/* Now we get the table name from the record */ /* Now we get the table name from the record */
field = rec_get_nth_field_old(rec, 1, &len); field = rec_get_nth_field_old(rec, 1, &len);
/* Load the table definition to memory */ /* 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); btr_pcur_close(&pcur);
mtr_commit(&mtr); mtr_commit(&mtr);
......
...@@ -177,10 +177,6 @@ dict_mem_table_add_col( ...@@ -177,10 +177,6 @@ dict_mem_table_add_col(
ulint len) /*!< in: precision */ ulint len) /*!< in: precision */
{ {
dict_col_t* col; dict_col_t* col;
#ifndef UNIV_HOTBACKUP
ulint mbminlen;
ulint mbmaxlen;
#endif /* !UNIV_HOTBACKUP */
ulint i; ulint i;
ut_ad(table); ut_ad(table);
...@@ -205,19 +201,7 @@ dict_mem_table_add_col( ...@@ -205,19 +201,7 @@ dict_mem_table_add_col(
col = dict_table_get_nth_col(table, i); col = dict_table_get_nth_col(table, i);
col->ind = (unsigned int) i; dict_mem_fill_column_struct(col, i, mtype, prtype, len);
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 */
} }
/**********************************************************************//** /**********************************************************************//**
...@@ -244,22 +228,9 @@ dict_mem_index_create( ...@@ -244,22 +228,9 @@ dict_mem_index_create(
heap = mem_heap_create(DICT_HEAP_SIZE); heap = mem_heap_create(DICT_HEAP_SIZE);
index = mem_heap_zalloc(heap, sizeof(dict_index_t)); 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); return(index);
} }
......
...@@ -11105,7 +11105,15 @@ i_s_innodb_lock_waits, ...@@ -11105,7 +11105,15 @@ i_s_innodb_lock_waits,
i_s_innodb_cmp, i_s_innodb_cmp,
i_s_innodb_cmp_reset, i_s_innodb_cmp_reset,
i_s_innodb_cmpmem, 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; mysql_declare_plugin_end;
/** @brief Initialize the default value of innodb_commit_concurrency. /** @brief Initialize the default value of innodb_commit_concurrency.
......
...@@ -36,12 +36,17 @@ Created July 18, 2007 Vasil Dimov ...@@ -36,12 +36,17 @@ Created July 18, 2007 Vasil Dimov
#include <mysql/innodb_priv.h> #include <mysql/innodb_priv.h>
extern "C" { extern "C" {
#include "trx0i_s.h" #include "btr0pcur.h" /* for file sys_tables related info. */
#include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */ #include "btr0types.h"
#include "buf0buddy.h" /* for i_s_cmpmem */ #include "buf0buddy.h" /* for i_s_cmpmem */
#include "buf0buf.h" /* for buf_pool and PAGE_ZIP_MIN_SIZE */ #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 "ha_prototypes.h" /* for innobase_convert_name() */
#include "srv0start.h" /* for srv_was_started */ #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"; static const char plugin_author[] = "Innobase Oy";
...@@ -131,7 +136,6 @@ int ...@@ -131,7 +136,6 @@ int
i_s_common_deinit( i_s_common_deinit(
/*==============*/ /*==============*/
void* p); /*!< in/out: table schema object */ void* p); /*!< in/out: table schema object */
/*******************************************************************//** /*******************************************************************//**
Auxiliary function to store time_t value in MYSQL_TYPE_DATETIME Auxiliary function to store time_t value in MYSQL_TYPE_DATETIME
field. field.
...@@ -1905,3 +1909,1660 @@ i_s_common_deinit( ...@@ -1905,3 +1909,1660 @@ i_s_common_deinit(
DBUG_RETURN(0); 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)
};
...@@ -33,5 +33,12 @@ extern struct st_mysql_plugin i_s_innodb_cmp; ...@@ -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_cmp_reset;
extern struct st_mysql_plugin i_s_innodb_cmpmem; 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_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 */ #endif /* i_s_h */
...@@ -765,7 +765,7 @@ dict_table_get_low( ...@@ -765,7 +765,7 @@ dict_table_get_low(
table = dict_table_check_if_in_cache_low(table_name); table = dict_table_check_if_in_cache_low(table_name);
if (table == NULL) { if (table == NULL) {
table = dict_load_table(table_name); table = dict_load_table(table_name, TRUE);
} }
ut_ad(!table || table->cached); ut_ad(!table || table->cached);
......
...@@ -31,6 +31,35 @@ Created 4/24/1996 Heikki Tuuri ...@@ -31,6 +31,35 @@ Created 4/24/1996 Heikki Tuuri
#include "dict0types.h" #include "dict0types.h"
#include "ut0byte.h" #include "ut0byte.h"
#include "mem0mem.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. In a crash recovery we already have all the tablespace objects created.
...@@ -54,6 +83,74 @@ char* ...@@ -54,6 +83,74 @@ char*
dict_get_first_table_name_in_db( dict_get_first_table_name_in_db(
/*============================*/ /*============================*/
const char* name); /*!< in: database name which ends to '/' */ 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 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 the cluster definition if the table is a member in a cluster. Also loads
...@@ -66,8 +163,9 @@ UNIV_INTERN ...@@ -66,8 +163,9 @@ UNIV_INTERN
dict_table_t* dict_table_t*
dict_load_table( dict_load_table(
/*============*/ /*============*/
const char* name); /*!< in: table name in the const char* name, /*!< in: table name in the
databasename/tablename format */ databasename/tablename format */
ibool cached);/*!< in: TRUE=add to cache, FALSE=do not */
/***********************************************************************//** /***********************************************************************//**
Loads a table object based on the table id. Loads a table object based on the table id.
@return table; NULL if table does not exist */ @return table; NULL if table does not exist */
...@@ -107,7 +205,113 @@ void ...@@ -107,7 +205,113 @@ void
dict_print(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 #ifndef UNIV_NONINL
#include "dict0load.ic" #include "dict0load.ic"
#endif #endif
......
...@@ -147,6 +147,36 @@ dict_mem_table_add_col( ...@@ -147,6 +147,36 @@ dict_mem_table_add_col(
ulint prtype, /*!< in: precise type */ ulint prtype, /*!< in: precise type */
ulint len); /*!< in: precision */ 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. Creates an index memory object.
@return own: index object */ @return own: index object */
UNIV_INTERN UNIV_INTERN
......
...@@ -23,4 +23,82 @@ Data dictionary memory object creation ...@@ -23,4 +23,82 @@ Data dictionary memory object creation
Created 1/8/1996 Heikki Tuuri 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 */
}
...@@ -3285,7 +3285,7 @@ row_drop_table_for_mysql( ...@@ -3285,7 +3285,7 @@ row_drop_table_for_mysql(
dict_table_remove_from_cache(table); dict_table_remove_from_cache(table);
if (dict_load_table(name) != NULL) { if (dict_load_table(name, TRUE) != NULL) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error: not able to remove table ", fputs(" InnoDB: Error: not able to remove table ",
stderr); stderr);
...@@ -3431,7 +3431,7 @@ row_mysql_drop_temp_tables(void) ...@@ -3431,7 +3431,7 @@ row_mysql_drop_temp_tables(void)
btr_pcur_store_position(&pcur, &mtr); btr_pcur_store_position(&pcur, &mtr);
btr_pcur_commit_specify_mtr(&pcur, &mtr); btr_pcur_commit_specify_mtr(&pcur, &mtr);
table = dict_load_table(table_name); table = dict_load_table(table_name, TRUE);
if (table) { if (table) {
row_drop_table_for_mysql(table_name, trx, FALSE); row_drop_table_for_mysql(table_name, trx, FALSE);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment