1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

MDEV-25743: Unnecessary copying of table names in InnoDB dictionary

Many InnoDB data dictionary cache operations require that the
table name be copied so that it will be NUL terminated.
(For example, SYS_TABLES.NAME is not guaranteed to be NUL-terminated.)

dict_table_t::is_garbage_name(): Check if a name belongs to
the background drop table queue.

dict_check_if_system_table_exists(): Remove.

dict_sys_t::load_sys_tables(): Load the non-hard-coded system tables
SYS_FOREIGN, SYS_FOREIGN_COLS, SYS_VIRTUAL on startup.

dict_sys_t::create_or_check_sys_tables(): Replaces
dict_create_or_check_foreign_constraint_tables() and
dict_create_or_check_sys_virtual().

dict_sys_t::load_table(): Replaces dict_table_get_low()
and dict_load_table().

dict_sys_t::find_table(): Renamed from get_table().

dict_sys_t::sys_tables_exist(): Check whether all the non-hard-coded
tables SYS_FOREIGN, SYS_FOREIGN_COLS, SYS_VIRTUAL exist.

trx_t::has_stats_table_lock(): Moved to dict0stats.cc.

Some error messages will now report table names in the internal
databasename/tablename format, instead of `databasename`.`tablename`.
This commit is contained in:
Marko Mäkelä
2021-05-20 14:58:25 +03:00
parent 525bf04910
commit 49e2c8f0a6
51 changed files with 915 additions and 1321 deletions

View File

@@ -71,7 +71,6 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA
#include <btr0sea.h> #include <btr0sea.h>
#include <dict0priv.h>
#include <lock0lock.h> #include <lock0lock.h>
#include <log0recv.h> #include <log0recv.h>
#include <log0crypt.h> #include <log0crypt.h>
@@ -3315,19 +3314,18 @@ static void xb_load_single_table_tablespace(const char *dirname,
name[pathlen - 5] = 0; name[pathlen - 5] = 0;
} }
const fil_space_t::name_type n{name, pathlen - 5};
Datafile *file; Datafile *file;
if (is_remote) { if (is_remote) {
RemoteDatafile* rf = new RemoteDatafile(); RemoteDatafile* rf = new RemoteDatafile();
if (!rf->open_link_file(name)) { if (!rf->open_link_file(n)) {
die("Can't open datafile %s", name); die("Can't open datafile %s", name);
} }
file = rf; file = rf;
} else { } else {
file = new Datafile(); file = new Datafile();
file->make_filepath(".", file->make_filepath(".", n, IBD);
fil_space_t::name_type{name, strlen(name)},
IBD);
} }
if (file->open_read_only(true) != DB_SUCCESS) { if (file->open_read_only(true) != DB_SUCCESS) {

View File

@@ -7,7 +7,7 @@
call mtr.add_suppression("\\[ERROR\\] InnoDB: Tablespace flags are invalid in datafile: .*test.t[rcd]\\.ibd"); call mtr.add_suppression("\\[ERROR\\] InnoDB: Tablespace flags are invalid in datafile: .*test.t[rcd]\\.ibd");
call mtr.add_suppression("\\[ERROR\\] InnoDB: Operating system error number .* in a file operation\\."); call mtr.add_suppression("\\[ERROR\\] InnoDB: Operating system error number .* in a file operation\\.");
call mtr.add_suppression("\\[ERROR\\] InnoDB: The error means the system cannot find the path specified\\."); call mtr.add_suppression("\\[ERROR\\] InnoDB: The error means the system cannot find the path specified\\.");
call mtr.add_suppression("\\[Warning\\] InnoDB: Ignoring tablespace for `test`\\.`td` because it could not be opened\\."); call mtr.add_suppression("\\[Warning\\] InnoDB: Ignoring tablespace for test/td because it could not be opened\\.");
CREATE TABLE tr(a INT)ENGINE=InnoDB ROW_FORMAT=REDUNDANT; CREATE TABLE tr(a INT)ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
CREATE TABLE tc(a INT)ENGINE=InnoDB ROW_FORMAT=COMPACT CREATE TABLE tc(a INT)ENGINE=InnoDB ROW_FORMAT=COMPACT
PAGE_COMPRESSED=1 PAGE_COMPRESSION_LEVEL=9; PAGE_COMPRESSED=1 PAGE_COMPRESSION_LEVEL=9;

View File

@@ -75,7 +75,7 @@ DROP TABLE t1;
Warnings: Warnings:
Warning 1932 Table 'test.t1' doesn't exist in engine Warning 1932 Table 'test.t1' doesn't exist in engine
DROP TABLE t2,t3; DROP TABLE t2,t3;
FOUND 5 /\[ERROR\] InnoDB: Table `test`\.`t1` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=1 SYS_TABLES\.MIX_LEN=511\b/ in mysqld.1.err FOUND 5 /\[ERROR\] InnoDB: Table test/t1 in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=1 SYS_TABLES\.MIX_LEN=511\b/ in mysqld.1.err
# restart # restart
ib_buffer_pool ib_buffer_pool
ib_logfile0 ib_logfile0

View File

@@ -122,8 +122,8 @@ a
42 42
SHOW CREATE TABLE tp; SHOW CREATE TABLE tp;
ERROR 42S02: Table 'test.tp' doesn't exist in engine ERROR 42S02: Table 'test.tp' doesn't exist in engine
FOUND 5 /InnoDB: Table `test`.`t[cp]` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=(129|289|3873|1232[13]) SYS_TABLES\.N_COLS=2147483649/ in mysqld.1.err FOUND 5 /InnoDB: Table test/t[cp] in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=(129|289|3873|1232[13]) SYS_TABLES\.N_COLS=2147483649/ in mysqld.1.err
FOUND 2 /InnoDB: Table `test`\.`tr` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=65 SYS_TABLES\.MIX_LEN=4294967295\b/ in mysqld.1.err FOUND 2 /InnoDB: Table test/tr in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=65 SYS_TABLES\.MIX_LEN=4294967295\b/ in mysqld.1.err
Restoring SYS_TABLES clustered index root page (8) Restoring SYS_TABLES clustered index root page (8)
# restart: with restart_parameters # restart: with restart_parameters
SHOW CREATE TABLE tr; SHOW CREATE TABLE tr;

View File

@@ -1,6 +1,6 @@
call mtr.add_suppression("InnoDB: Operating system error number "); call mtr.add_suppression("InnoDB: Operating system error number ");
call mtr.add_suppression("InnoDB: (The error means|If you are|Cannot open datafile) "); call mtr.add_suppression("InnoDB: (The error means|If you are|Cannot open datafile) ");
call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\.`t`"); call mtr.add_suppression("InnoDB: Ignoring tablespace for test/t ");
call mtr.add_suppression("InnoDB: Table test/t .* does not exist"); call mtr.add_suppression("InnoDB: Table test/t .* does not exist");
CREATE TABLE t (a SERIAL) ENGINE=InnoDB; CREATE TABLE t (a SERIAL) ENGINE=InnoDB;
INSERT INTO t() VALUES(); INSERT INTO t() VALUES();

View File

@@ -10,7 +10,7 @@
call mtr.add_suppression("InnoDB: Cannot open datafile for read-only: "); call mtr.add_suppression("InnoDB: Cannot open datafile for read-only: ");
call mtr.add_suppression("InnoDB: Operating system error number .* in a file operation"); call mtr.add_suppression("InnoDB: Operating system error number .* in a file operation");
call mtr.add_suppression("InnoDB: The error means the system cannot find the path specified"); call mtr.add_suppression("InnoDB: The error means the system cannot find the path specified");
call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`.`\(t\|x\.\.d\)` because it could not be opened"); call mtr.add_suppression("InnoDB: Ignoring tablespace for test/\(t\|x@002e@002ed\) because it could not be opened");
call mtr.add_suppression("InnoDB: Cannot calculate statistics for table .* because the .ibd file is missing"); call mtr.add_suppression("InnoDB: Cannot calculate statistics for table .* because the .ibd file is missing");
call mtr.add_suppression("Could not find a valid tablespace file for"); call mtr.add_suppression("Could not find a valid tablespace file for");
call mtr.add_suppression("InnoDB: Failed to find tablespace for table `test`\.`\(t\|x\.\.d\)` in the cache"); call mtr.add_suppression("InnoDB: Failed to find tablespace for table `test`\.`\(t\|x\.\.d\)` in the cache");

View File

@@ -164,7 +164,7 @@ call mtr.add_suppression("InnoDB: The error means the system cannot find the pat
call mtr.add_suppression("InnoDB: .*you must create directories"); call mtr.add_suppression("InnoDB: .*you must create directories");
call mtr.add_suppression("InnoDB: Cannot open datafile for read-only: '.*u[1-5]\.ibd'"); call mtr.add_suppression("InnoDB: Cannot open datafile for read-only: '.*u[1-5]\.ibd'");
call mtr.add_suppression("InnoDB: Could not find a valid tablespace file for `test/u[1-5]`"); call mtr.add_suppression("InnoDB: Could not find a valid tablespace file for `test/u[1-5]`");
call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`.`u[1-3]` because it could not be opened."); call mtr.add_suppression("InnoDB: Ignoring tablespace for test/u[1-3] because it could not be opened\\.");
call mtr.add_suppression("InnoDB: Failed to find tablespace for table .* in the cache. Attempting to load the tablespace with space id"); call mtr.add_suppression("InnoDB: Failed to find tablespace for table .* in the cache. Attempting to load the tablespace with space id");
call mtr.add_suppression("InnoDB: Plugin initialization aborted"); call mtr.add_suppression("InnoDB: Plugin initialization aborted");
call mtr.add_suppression("Plugin 'InnoDB' \(init function returned error\|registration as a STORAGE ENGINE failed\)"); call mtr.add_suppression("Plugin 'InnoDB' \(init function returned error\|registration as a STORAGE ENGINE failed\)");

View File

@@ -18,7 +18,7 @@ let page_size= `select @@innodb_page_size`;
call mtr.add_suppression("\\[ERROR\\] InnoDB: Tablespace flags are invalid in datafile: .*test.t[rcd]\\.ibd"); call mtr.add_suppression("\\[ERROR\\] InnoDB: Tablespace flags are invalid in datafile: .*test.t[rcd]\\.ibd");
call mtr.add_suppression("\\[ERROR\\] InnoDB: Operating system error number .* in a file operation\\."); call mtr.add_suppression("\\[ERROR\\] InnoDB: Operating system error number .* in a file operation\\.");
call mtr.add_suppression("\\[ERROR\\] InnoDB: The error means the system cannot find the path specified\\."); call mtr.add_suppression("\\[ERROR\\] InnoDB: The error means the system cannot find the path specified\\.");
call mtr.add_suppression("\\[Warning\\] InnoDB: Ignoring tablespace for `test`\\.`td` because it could not be opened\\."); call mtr.add_suppression("\\[Warning\\] InnoDB: Ignoring tablespace for test/td because it could not be opened\\.");
CREATE TABLE tr(a INT)ENGINE=InnoDB ROW_FORMAT=REDUNDANT; CREATE TABLE tr(a INT)ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
CREATE TABLE tc(a INT)ENGINE=InnoDB ROW_FORMAT=COMPACT CREATE TABLE tc(a INT)ENGINE=InnoDB ROW_FORMAT=COMPACT

View File

@@ -4,7 +4,7 @@
--disable_query_log --disable_query_log
call mtr.add_suppression("InnoDB: Table `mysql`\\.`innodb_table_stats` not found"); call mtr.add_suppression("InnoDB: Table `mysql`\\.`innodb_table_stats` not found");
call mtr.add_suppression("InnoDB: Table `test`.`t1` in InnoDB data dictionary contains invalid flags. SYS_TABLES\\.TYPE=1 SYS_TABLES\\.MIX_LEN=511\\r?$"); call mtr.add_suppression("InnoDB: Table test/t1 in InnoDB data dictionary contains invalid flags. SYS_TABLES\\.TYPE=1 SYS_TABLES\\.MIX_LEN=511\\r?$");
call mtr.add_suppression("InnoDB: Parent table of FTS auxiliary table test/FTS_.* not found"); call mtr.add_suppression("InnoDB: Parent table of FTS auxiliary table test/FTS_.* not found");
call mtr.add_suppression("InnoDB: Cannot open table test/t1 from the internal data dictionary"); call mtr.add_suppression("InnoDB: Cannot open table test/t1 from the internal data dictionary");
call mtr.add_suppression("InnoDB: Table `test`.`t1` does not exist in the InnoDB internal data dictionary though MariaDB is trying to (rename|drop)"); call mtr.add_suppression("InnoDB: Table `test`.`t1` does not exist in the InnoDB internal data dictionary though MariaDB is trying to (rename|drop)");
@@ -153,7 +153,7 @@ RENAME TABLE t1 TO tee_one;
DROP TABLE t1; DROP TABLE t1;
DROP TABLE t2,t3; DROP TABLE t2,t3;
--let SEARCH_PATTERN= \[ERROR\] InnoDB: Table `test`\.`t1` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=1 SYS_TABLES\.MIX_LEN=511\b --let SEARCH_PATTERN= \[ERROR\] InnoDB: Table test/t1 in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=1 SYS_TABLES\.MIX_LEN=511\b
--source include/search_pattern_in_file.inc --source include/search_pattern_in_file.inc
--let $restart_parameters= --let $restart_parameters=

View File

@@ -6,8 +6,8 @@
--disable_query_log --disable_query_log
call mtr.add_suppression("InnoDB: Table `mysql`\\.`innodb_table_stats` not found"); call mtr.add_suppression("InnoDB: Table `mysql`\\.`innodb_table_stats` not found");
call mtr.add_suppression("InnoDB: incorrect flags in SYS_TABLES"); call mtr.add_suppression("InnoDB: incorrect flags in SYS_TABLES");
call mtr.add_suppression("InnoDB: Table `test`.`t[cp]` in InnoDB data dictionary contains invalid flags\\. SYS_TABLES\\.TYPE=(129|289|3873|1232[31]) SYS_TABLES\\.N_COLS=2147483649\\r?$"); call mtr.add_suppression("InnoDB: Table test/t[cp] in InnoDB data dictionary contains invalid flags\\. SYS_TABLES\\.TYPE=(129|289|3873|1232[31]) SYS_TABLES\\.N_COLS=2147483649\\r?$");
call mtr.add_suppression("InnoDB: Table `test`\\.`tr` in InnoDB data dictionary contains invalid flags\\. SYS_TABLES\\.TYPE=65 SYS_TABLES\\.MIX_LEN=4294967295\\r?$"); call mtr.add_suppression("InnoDB: Table test/tr in InnoDB data dictionary contains invalid flags\\. SYS_TABLES\\.TYPE=65 SYS_TABLES\\.MIX_LEN=4294967295\\r?$");
call mtr.add_suppression("InnoDB: Refusing to load '\\..test.td\\.ibd' \\(id=3, flags=0x([2e]1)\\); dictionary contains id=3, flags=0x100\\1\\r?$"); call mtr.add_suppression("InnoDB: Refusing to load '\\..test.td\\.ibd' \\(id=3, flags=0x([2e]1)\\); dictionary contains id=3, flags=0x100\\1\\r?$");
call mtr.add_suppression("InnoDB: Refusing to load '\\..test.td\\.ibd' \\(id=3, flags=0x(1[2ae]1)\\); dictionary contains id=3, flags=0x10\\1\\r?$"); call mtr.add_suppression("InnoDB: Refusing to load '\\..test.td\\.ibd' \\(id=3, flags=0x(1[2ae]1)\\); dictionary contains id=3, flags=0x10\\1\\r?$");
call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`.`td` because it could not be opened\\."); call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`.`td` because it could not be opened\\.");
@@ -170,9 +170,9 @@ SHOW CREATE TABLE tp;
--source include/shutdown_mysqld.inc --source include/shutdown_mysqld.inc
let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err; let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err;
--let SEARCH_PATTERN= InnoDB: Table `test`.`t[cp]` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=(129|289|3873|1232[13]) SYS_TABLES\.N_COLS=2147483649 --let SEARCH_PATTERN= InnoDB: Table test/t[cp] in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=(129|289|3873|1232[13]) SYS_TABLES\.N_COLS=2147483649
--source include/search_pattern_in_file.inc --source include/search_pattern_in_file.inc
--let SEARCH_PATTERN= InnoDB: Table `test`\.`tr` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=65 SYS_TABLES\.MIX_LEN=4294967295\b --let SEARCH_PATTERN= InnoDB: Table test/tr in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=65 SYS_TABLES\.MIX_LEN=4294967295\b
--source include/search_pattern_in_file.inc --source include/search_pattern_in_file.inc
# Restore the backup of the corrupted SYS_TABLES clustered index root page # Restore the backup of the corrupted SYS_TABLES clustered index root page

View File

@@ -3,7 +3,7 @@
call mtr.add_suppression("InnoDB: Operating system error number "); call mtr.add_suppression("InnoDB: Operating system error number ");
call mtr.add_suppression("InnoDB: (The error means|If you are|Cannot open datafile) "); call mtr.add_suppression("InnoDB: (The error means|If you are|Cannot open datafile) ");
call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\.`t`"); call mtr.add_suppression("InnoDB: Ignoring tablespace for test/t ");
call mtr.add_suppression("InnoDB: Table test/t .* does not exist"); call mtr.add_suppression("InnoDB: Table test/t .* does not exist");
CREATE TABLE t (a SERIAL) ENGINE=InnoDB; CREATE TABLE t (a SERIAL) ENGINE=InnoDB;

View File

@@ -252,7 +252,7 @@ if (!$have_debug)
call mtr.add_suppression("InnoDB: Cannot (read first page of|open datafile for read-only:) '\\./test/(FTS_|#sql-(alter|backup)-).*\\.ibd'"); call mtr.add_suppression("InnoDB: Cannot (read first page of|open datafile for read-only:) '\\./test/(FTS_|#sql-(alter|backup)-).*\\.ibd'");
call mtr.add_suppression("InnoDB: Datafile '\\./test/(FTS_|#sql-(alter|backup)-).*\\.ibd' is corrupted"); call mtr.add_suppression("InnoDB: Datafile '\\./test/(FTS_|#sql-(alter|backup)-).*\\.ibd' is corrupted");
call mtr.add_suppression("InnoDB: (The error means|Operating system error)"); call mtr.add_suppression("InnoDB: (The error means|Operating system error)");
call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\\.`(FTS_|#sql-(backup|alter)-).*` because it could not be opened\\."); call mtr.add_suppression("InnoDB: Ignoring tablespace for test/(FTS_|#sql-(backup|alter)-).* because it could not be opened\\.");
call mtr.add_suppression("InnoDB: Expected tablespace id [1-9][0-9]* but found 0 in the file .*/test/(FTS_|#sql-(alter|backup)-).*\\.ibd"); call mtr.add_suppression("InnoDB: Expected tablespace id [1-9][0-9]* but found 0 in the file .*/test/(FTS_|#sql-(alter|backup)-).*\\.ibd");
--enable_query_log --enable_query_log
} }

View File

@@ -7,7 +7,7 @@ call mtr.add_suppression("InnoDB: Unknown index id .* on page");
call mtr.add_suppression("InnoDB: Operating system error number"); call mtr.add_suppression("InnoDB: Operating system error number");
call mtr.add_suppression("InnoDB: The error means"); call mtr.add_suppression("InnoDB: The error means");
call mtr.add_suppression("InnoDB: Cannot open datafile .*t1\\.ibd"); call mtr.add_suppression("InnoDB: Cannot open datafile .*t1\\.ibd");
call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\\.`t1`"); call mtr.add_suppression("InnoDB: Ignoring tablespace for test/t1 ");
FLUSH TABLES; FLUSH TABLES;
SET SESSION innodb_strict_mode=1; SET SESSION innodb_strict_mode=1;
CREATE TABLE t1 (c1 INT) ENGINE = Innodb CREATE TABLE t1 (c1 INT) ENGINE = Innodb

View File

@@ -23,7 +23,7 @@ call mtr.add_suppression("InnoDB: Unknown index id .* on page");
call mtr.add_suppression("InnoDB: Operating system error number"); call mtr.add_suppression("InnoDB: Operating system error number");
call mtr.add_suppression("InnoDB: The error means"); call mtr.add_suppression("InnoDB: The error means");
call mtr.add_suppression("InnoDB: Cannot open datafile .*t1\\.ibd"); call mtr.add_suppression("InnoDB: Cannot open datafile .*t1\\.ibd");
call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\\.`t1`"); call mtr.add_suppression("InnoDB: Ignoring tablespace for test/t1 ");
FLUSH TABLES; FLUSH TABLES;
let MYSQLD_DATADIR =`SELECT @@datadir`; let MYSQLD_DATADIR =`SELECT @@datadir`;

View File

@@ -12,7 +12,7 @@ call mtr.add_suppression("InnoDB: Cannot open datafile for read-only: '.*test.t1
call mtr.add_suppression('InnoDB: Operating system error number'); call mtr.add_suppression('InnoDB: Operating system error number');
call mtr.add_suppression('InnoDB: The error means the system cannot find the path specified\.'); call mtr.add_suppression('InnoDB: The error means the system cannot find the path specified\.');
call mtr.add_suppression('InnoDB: Table test/t1 in the InnoDB data dictionary has tablespace id .*, but tablespace with that id or name does not exist'); call mtr.add_suppression('InnoDB: Table test/t1 in the InnoDB data dictionary has tablespace id .*, but tablespace with that id or name does not exist');
call mtr.add_suppression('InnoDB: Ignoring tablespace for `test`\.`t1` because it could not be opened\.'); call mtr.add_suppression('InnoDB: Ignoring tablespace for test/t1 because it could not be opened\.');
--enable_query_log --enable_query_log
--source include/shutdown_mysqld.inc --source include/shutdown_mysqld.inc

View File

@@ -115,8 +115,6 @@ SET(INNOBASE_SOURCES
include/dict0mem.ic include/dict0mem.ic
include/dict0pagecompress.h include/dict0pagecompress.h
include/dict0pagecompress.ic include/dict0pagecompress.ic
include/dict0priv.h
include/dict0priv.ic
include/dict0stats.h include/dict0stats.h
include/dict0stats.ic include/dict0stats.ic
include/dict0stats_bg.h include/dict0stats_bg.h

View File

@@ -96,45 +96,41 @@ void dict_hdr_flush_row_id(row_id_t id)
mtr.commit(); mtr.commit();
} }
/*****************************************************************//** /** Create the DICT_HDR page on database initialization.
Creates the file page for the dictionary header. This function is @return whether the operation failed */
called only at the database creation. static bool dict_hdr_create()
@return TRUE if succeed */
static
ibool
dict_hdr_create(
/*============*/
mtr_t* mtr) /*!< in: mtr */
{ {
buf_block_t* block; buf_block_t* block;
ulint root_page_no; ulint root_page_no;
ut_ad(mtr); bool fail = false;
mtr_t mtr;
mtr.start();
compile_time_assert(DICT_HDR_SPACE == 0); compile_time_assert(DICT_HDR_SPACE == 0);
/* Create the dictionary header file block in a new, allocated file /* Create the dictionary header file block in a new, allocated file
segment in the system tablespace */ segment in the system tablespace */
block = fseg_create(fil_system.sys_space, block = fseg_create(fil_system.sys_space,
DICT_HDR + DICT_HDR_FSEG_HEADER, mtr); DICT_HDR + DICT_HDR_FSEG_HEADER, &mtr);
ut_a(block->page.id() == page_id_t(DICT_HDR_SPACE, DICT_HDR_PAGE_NO)); ut_a(block->page.id() == page_id_t(DICT_HDR_SPACE, DICT_HDR_PAGE_NO));
buf_block_t* d = dict_hdr_get(mtr); buf_block_t* d = dict_hdr_get(&mtr);
/* Start counting row, table, index, and tree ids from /* Start counting row, table, index, and tree ids from
DICT_HDR_FIRST_ID */ DICT_HDR_FIRST_ID */
mtr->write<8>(*d, DICT_HDR + DICT_HDR_ROW_ID + d->frame, mtr.write<8>(*d, DICT_HDR + DICT_HDR_ROW_ID + d->frame,
DICT_HDR_FIRST_ID); DICT_HDR_FIRST_ID);
mtr->write<8>(*d, DICT_HDR + DICT_HDR_TABLE_ID + d->frame, mtr.write<8>(*d, DICT_HDR + DICT_HDR_TABLE_ID + d->frame,
DICT_HDR_FIRST_ID); DICT_HDR_FIRST_ID);
mtr->write<8>(*d, DICT_HDR + DICT_HDR_INDEX_ID + d->frame, mtr.write<8>(*d, DICT_HDR + DICT_HDR_INDEX_ID + d->frame,
DICT_HDR_FIRST_ID); DICT_HDR_FIRST_ID);
ut_ad(!mach_read_from_4(DICT_HDR + DICT_HDR_MAX_SPACE_ID + d->frame)); ut_ad(!mach_read_from_4(DICT_HDR + DICT_HDR_MAX_SPACE_ID + d->frame));
/* Obsolete, but we must initialize it anyway. */ /* Obsolete, but we must initialize it anyway. */
mtr->write<4>(*d, DICT_HDR + DICT_HDR_MIX_ID_LOW + d->frame, mtr.write<4>(*d, DICT_HDR + DICT_HDR_MIX_ID_LOW + d->frame,
DICT_HDR_FIRST_ID); DICT_HDR_FIRST_ID);
/* Create the B-tree roots for the clustered indexes of the basic /* Create the B-tree roots for the clustered indexes of the basic
system tables */ system tables */
@@ -142,59 +138,55 @@ dict_hdr_create(
/*--------------------------*/ /*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
fil_system.sys_space, DICT_TABLES_ID, fil_system.sys_space, DICT_TABLES_ID,
nullptr, mtr); nullptr, &mtr);
if (root_page_no == FIL_NULL) { if (root_page_no == FIL_NULL) {
failed:
return(FALSE); fail = true;
goto func_exit;
} }
mtr->write<4>(*d, DICT_HDR + DICT_HDR_TABLES + d->frame, root_page_no); mtr.write<4>(*d, DICT_HDR + DICT_HDR_TABLES + d->frame, root_page_no);
/*--------------------------*/ /*--------------------------*/
root_page_no = btr_create(DICT_UNIQUE, root_page_no = btr_create(DICT_UNIQUE,
fil_system.sys_space, DICT_TABLE_IDS_ID, fil_system.sys_space, DICT_TABLE_IDS_ID,
nullptr, mtr); nullptr, &mtr);
if (root_page_no == FIL_NULL) { if (root_page_no == FIL_NULL) {
goto failed;
return(FALSE);
} }
mtr->write<4>(*d, DICT_HDR + DICT_HDR_TABLE_IDS + d->frame, mtr.write<4>(*d, DICT_HDR + DICT_HDR_TABLE_IDS + d->frame,
root_page_no); root_page_no);
/*--------------------------*/ /*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
fil_system.sys_space, DICT_COLUMNS_ID, fil_system.sys_space, DICT_COLUMNS_ID,
nullptr, mtr); nullptr, &mtr);
if (root_page_no == FIL_NULL) { if (root_page_no == FIL_NULL) {
goto failed;
return(FALSE);
} }
mtr->write<4>(*d, DICT_HDR + DICT_HDR_COLUMNS + d->frame, mtr.write<4>(*d, DICT_HDR + DICT_HDR_COLUMNS + d->frame,
root_page_no); root_page_no);
/*--------------------------*/ /*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
fil_system.sys_space, DICT_INDEXES_ID, fil_system.sys_space, DICT_INDEXES_ID,
nullptr, mtr); nullptr, &mtr);
if (root_page_no == FIL_NULL) { if (root_page_no == FIL_NULL) {
goto failed;
return(FALSE);
} }
mtr->write<4>(*d, DICT_HDR + DICT_HDR_INDEXES + d->frame, mtr.write<4>(*d, DICT_HDR + DICT_HDR_INDEXES + d->frame, root_page_no);
root_page_no);
/*--------------------------*/ /*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
fil_system.sys_space, DICT_FIELDS_ID, fil_system.sys_space, DICT_FIELDS_ID,
nullptr, mtr); nullptr, &mtr);
if (root_page_no == FIL_NULL) { if (root_page_no == FIL_NULL) {
goto failed;
return(FALSE);
} }
mtr->write<4>(*d, DICT_HDR + DICT_HDR_FIELDS + d->frame, root_page_no); mtr.write<4>(*d, DICT_HDR + DICT_HDR_FIELDS + d->frame, root_page_no);
/*--------------------------*/ func_exit:
mtr.commit();
return(TRUE); return fail;
} }
/*****************************************************************//** /*****************************************************************//**
@@ -210,23 +202,21 @@ dict_boot(void)
mem_heap_t* heap; mem_heap_t* heap;
mtr_t mtr; mtr_t mtr;
/* Be sure these constants do not ever change. To avoid bloat, static_assert(DICT_NUM_COLS__SYS_TABLES == 8, "compatibility");
only check the *NUM_FIELDS* in each table */ static_assert(DICT_NUM_FIELDS__SYS_TABLES == 10, "compatibility");
static_assert(DICT_NUM_FIELDS__SYS_TABLE_IDS == 2, "compatibility");
ut_ad(DICT_NUM_COLS__SYS_TABLES == 8); static_assert(DICT_NUM_COLS__SYS_COLUMNS == 7, "compatibility");
ut_ad(DICT_NUM_FIELDS__SYS_TABLES == 10); static_assert(DICT_NUM_FIELDS__SYS_COLUMNS == 9, "compatibility");
ut_ad(DICT_NUM_FIELDS__SYS_TABLE_IDS == 2); static_assert(DICT_NUM_COLS__SYS_INDEXES == 8, "compatibility");
ut_ad(DICT_NUM_COLS__SYS_COLUMNS == 7); static_assert(DICT_NUM_FIELDS__SYS_INDEXES == 10, "compatibility");
ut_ad(DICT_NUM_FIELDS__SYS_COLUMNS == 9); static_assert(DICT_NUM_COLS__SYS_FIELDS == 3, "compatibility");
ut_ad(DICT_NUM_COLS__SYS_INDEXES == 8); static_assert(DICT_NUM_FIELDS__SYS_FIELDS == 5, "compatibility");
ut_ad(DICT_NUM_FIELDS__SYS_INDEXES == 10); static_assert(DICT_NUM_COLS__SYS_FOREIGN == 4, "compatibility");
ut_ad(DICT_NUM_COLS__SYS_FIELDS == 3); static_assert(DICT_NUM_FIELDS__SYS_FOREIGN == 6, "compatibility");
ut_ad(DICT_NUM_FIELDS__SYS_FIELDS == 5); static_assert(DICT_NUM_FIELDS__SYS_FOREIGN_FOR_NAME == 2,
ut_ad(DICT_NUM_COLS__SYS_FOREIGN == 4); "compatibility");
ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN == 6); static_assert(DICT_NUM_COLS__SYS_FOREIGN_COLS == 4, "compatibility");
ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN_FOR_NAME == 2); static_assert(DICT_NUM_FIELDS__SYS_FOREIGN_COLS == 6, "compatibility");
ut_ad(DICT_NUM_COLS__SYS_FOREIGN_COLS == 4);
ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN_COLS == 6);
mtr_start(&mtr); mtr_start(&mtr);
@@ -260,9 +250,9 @@ dict_boot(void)
/* Insert into the dictionary cache the descriptions of the basic /* Insert into the dictionary cache the descriptions of the basic
system tables */ system tables */
/*-------------------------*/ /*-------------------------*/
table = dict_mem_table_create("SYS_TABLES", fil_system.sys_space, table = dict_table_t::create(dict_sys.SYS_TABLE[dict_sys.SYS_TABLES],
8, 0, 0, 0); fil_system.sys_space,
DICT_NUM_COLS__SYS_TABLES, 0, 0, 0);
dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0,
MAX_FULL_NAME_LEN); MAX_FULL_NAME_LEN);
dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 8); dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 8);
@@ -308,9 +298,9 @@ dict_boot(void)
ut_a(error == DB_SUCCESS); ut_a(error == DB_SUCCESS);
/*-------------------------*/ /*-------------------------*/
table = dict_mem_table_create("SYS_COLUMNS", fil_system.sys_space, table = dict_table_t::create(dict_sys.SYS_TABLE[dict_sys.SYS_COLUMNS],
7, 0, 0, 0); fil_system.sys_space,
DICT_NUM_COLS__SYS_COLUMNS, 0, 0, 0);
dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 8); dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 8);
dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0);
@@ -341,8 +331,9 @@ dict_boot(void)
UT_BITS_IN_BYTES(unsigned(table->indexes.start->n_nullable))); UT_BITS_IN_BYTES(unsigned(table->indexes.start->n_nullable)));
/*-------------------------*/ /*-------------------------*/
table = dict_mem_table_create("SYS_INDEXES", fil_system.sys_space, table = dict_table_t::create(dict_sys.SYS_TABLE[dict_sys.SYS_INDEXES],
DICT_NUM_COLS__SYS_INDEXES, 0, 0, 0); fil_system.sys_space,
DICT_NUM_COLS__SYS_INDEXES, 0, 0, 0);
dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 8); dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 8);
dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 8); dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 8);
@@ -383,9 +374,9 @@ dict_boot(void)
UT_BITS_IN_BYTES(unsigned(table->indexes.start->n_nullable))); UT_BITS_IN_BYTES(unsigned(table->indexes.start->n_nullable)));
/*-------------------------*/ /*-------------------------*/
table = dict_mem_table_create("SYS_FIELDS", fil_system.sys_space, table = dict_table_t::create(dict_sys.SYS_TABLE[dict_sys.SYS_FIELDS],
3, 0, 0, 0); fil_system.sys_space,
DICT_NUM_COLS__SYS_FIELDS, 0, 0, 0);
dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 8); dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 8);
dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "COL_NAME", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "COL_NAME", DATA_BINARY, 0, 0);
@@ -413,10 +404,6 @@ dict_boot(void)
mtr_commit(&mtr); mtr_commit(&mtr);
/*-------------------------*/
/* Initialize the insert buffer table and index for each tablespace */
dberr_t err = ibuf_init_at_db_start(); dberr_t err = ibuf_init_at_db_start();
if (err == DB_SUCCESS) { if (err == DB_SUCCESS) {
@@ -426,44 +413,19 @@ dict_boot(void)
dict_load_sys_table(dict_sys.sys_columns); dict_load_sys_table(dict_sys.sys_columns);
dict_load_sys_table(dict_sys.sys_indexes); dict_load_sys_table(dict_sys.sys_indexes);
dict_load_sys_table(dict_sys.sys_fields); dict_load_sys_table(dict_sys.sys_fields);
dict_sys.mutex_unlock();
dict_sys.load_sys_tables();
} else {
dict_sys.mutex_unlock();
} }
dict_sys.mutex_unlock();
return(err); return(err);
} }
/*****************************************************************//**
Inserts the basic system table data into themselves in the database
creation. */
static
void
dict_insert_initial_data(void)
/*==========================*/
{
/* Does nothing yet */
}
/*****************************************************************//** /*****************************************************************//**
Creates and initializes the data dictionary at the server bootstrap. Creates and initializes the data dictionary at the server bootstrap.
@return DB_SUCCESS or error code. */ @return DB_SUCCESS or error code. */
dberr_t dberr_t dict_create()
dict_create(void)
/*=============*/
{ {
mtr_t mtr; return dict_hdr_create() ? DB_ERROR : dict_boot();
mtr_start(&mtr);
dict_hdr_create(&mtr);
mtr_commit(&mtr);
dberr_t err = dict_boot();
if (err == DB_SUCCESS) {
dict_insert_initial_data();
}
return(err);
} }

View File

@@ -41,9 +41,9 @@ Created 1/8/1996 Heikki Tuuri
#include "trx0rseg.h" #include "trx0rseg.h"
#include "trx0undo.h" #include "trx0undo.h"
#include "ut0vec.h" #include "ut0vec.h"
#include "dict0priv.h"
#include "fts0priv.h" #include "fts0priv.h"
#include "srv0start.h" #include "srv0start.h"
#include "log.h"
/*****************************************************************//** /*****************************************************************//**
Based on a table object, this function builds the entry to be inserted Based on a table object, this function builds the entry to be inserted
@@ -897,6 +897,17 @@ rec_corrupted:
return 0; return 0;
} }
/** @return whether SYS_TABLES.NAME is for a '#sql-ib' table */
bool dict_table_t::is_garbage_name(const void *data, size_t size)
{
constexpr size_t suffix= sizeof TEMP_FILE_PREFIX_INNODB;
if (size <= suffix)
return false;
const char *f= static_cast<const char*>(memchr(data, '/', size - suffix));
return f && !memcmp(f + 1, TEMP_FILE_PREFIX_INNODB,
(sizeof TEMP_FILE_PREFIX_INNODB) - 1);
}
/*********************************************************************//** /*********************************************************************//**
Creates a table create graph. Creates a table create graph.
@return own: table create node */ @return own: table create node */
@@ -1315,259 +1326,196 @@ function_exit:
return(thr); return(thr);
} }
/****************************************************************//** bool dict_sys_t::load_sys_tables()
Check whether a system table exists. Additionally, if it exists,
move it to the non-LRU end of the table LRU list. This is only used
for system tables that can be upgraded or added to an older database,
which include SYS_FOREIGN and SYS_FOREIGN_COLS.
@return DB_SUCCESS if the sys table exists, DB_CORRUPTION if it exists
but is not current, DB_TABLE_NOT_FOUND if it does not exist*/
static
dberr_t
dict_check_if_system_table_exists(
/*==============================*/
const char* tablename, /*!< in: name of table */
ulint num_fields, /*!< in: number of fields */
ulint num_indexes) /*!< in: number of indexes */
{ {
dict_table_t* sys_table; ut_ad(!srv_any_background_activity());
dberr_t error = DB_SUCCESS; bool mismatch= false;
mutex_lock();
ut_ad(!srv_any_background_activity()); if (!(sys_foreign= load_table(SYS_TABLE[SYS_FOREIGN],
DICT_ERR_IGNORE_FK_NOKEY)));
dict_sys.mutex_lock(); else if (UT_LIST_GET_LEN(sys_foreign->indexes) == 3 &&
sys_foreign->n_cols == DICT_NUM_COLS__SYS_FOREIGN + DATA_N_SYS_COLS)
sys_table = dict_table_get_low(tablename); prevent_eviction(sys_foreign);
else
if (sys_table == NULL) { {
error = DB_TABLE_NOT_FOUND; sys_foreign= nullptr;
mismatch= true;
} else if (UT_LIST_GET_LEN(sys_table->indexes) != num_indexes ib::error() << "Invalid definition of SYS_FOREIGN";
|| sys_table->n_cols != num_fields) { }
error = DB_CORRUPTION; if (!(sys_foreign_cols= load_table(SYS_TABLE[SYS_FOREIGN_COLS],
DICT_ERR_IGNORE_FK_NOKEY)));
} else { else if (UT_LIST_GET_LEN(sys_foreign_cols->indexes) == 1 &&
/* This table has already been created, and it is OK. sys_foreign_cols->n_cols ==
Ensure that it can't be evicted from the table LRU cache. */ DICT_NUM_COLS__SYS_FOREIGN_COLS + DATA_N_SYS_COLS)
prevent_eviction(sys_foreign_cols);
dict_table_prevent_eviction(sys_table); else
} {
sys_foreign_cols= nullptr;
dict_sys.mutex_unlock(); mismatch= true;
ib::error() << "Invalid definition of SYS_FOREIGN_COLS";
return(error); }
if (!(sys_virtual= load_table(SYS_TABLE[SYS_VIRTUAL],
DICT_ERR_IGNORE_FK_NOKEY)));
else if (UT_LIST_GET_LEN(sys_virtual->indexes) == 1 &&
sys_virtual->n_cols == DICT_NUM_COLS__SYS_VIRTUAL + DATA_N_SYS_COLS)
prevent_eviction(sys_virtual);
else
{
sys_virtual= nullptr;
mismatch= true;
ib::error() << "Invalid definition of SYS_VIRTUAL";
}
mutex_unlock();
return mismatch;
} }
/****************************************************************//** dberr_t dict_sys_t::create_or_check_sys_tables()
Creates the foreign key constraints system tables inside InnoDB
at server bootstrap or server start if they are not found or are
not of the right form.
@return DB_SUCCESS or error code */
dberr_t
dict_create_or_check_foreign_constraint_tables(void)
/*================================================*/
{ {
trx_t* trx; if (sys_tables_exist())
my_bool srv_file_per_table_backup; return DB_SUCCESS;
dberr_t err;
dberr_t sys_foreign_err;
dberr_t sys_foreign_cols_err;
ut_ad(!srv_any_background_activity()); if (srv_read_only_mode || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO)
return DB_READ_ONLY;
sys_foreign_err = dict_check_if_system_table_exists( if (load_sys_tables())
"SYS_FOREIGN", DICT_NUM_FIELDS__SYS_FOREIGN + 1, 3); {
sys_foreign_cols_err = dict_check_if_system_table_exists( ib::info() << "Set innodb_read_only=1 or innodb_force_recovery=3"
"SYS_FOREIGN_COLS", DICT_NUM_FIELDS__SYS_FOREIGN_COLS + 1, 1); " to start up";
return DB_CORRUPTION;
}
if (sys_foreign_err == DB_SUCCESS if (sys_tables_exist())
&& sys_foreign_cols_err == DB_SUCCESS) { return DB_SUCCESS;
return(DB_SUCCESS);
}
if (srv_read_only_mode trx_t *trx= trx_create();
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO) { trx->dict_operation = true;
return(DB_READ_ONLY); row_mysql_lock_data_dictionary(trx);
}
trx = trx_create(); DBUG_EXECUTE_IF("create_and_drop_garbage",
ut_ad(DB_SUCCESS == que_eval_sql(
nullptr,
"PROCEDURE CREATE_GARBAGE_TABLE_PROC () IS\n"
"BEGIN\n"
"CREATE TABLE\n"
"\"test/" TEMP_FILE_PREFIX_INNODB "-garbage\""
"(ID CHAR);\n"
"CREATE UNIQUE CLUSTERED INDEX PRIMARY ON "
"\"test/" TEMP_FILE_PREFIX_INNODB
"-garbage\"(ID);\n"
"END;\n", false, trx));
row_drop_table_for_mysql("test/"
TEMP_FILE_PREFIX_INNODB "-garbage",
trx, SQLCOM_DROP_DB, true););
trx->dict_operation = true; /* NOTE: when designing InnoDB's foreign key support in 2001, Heikki Tuuri
made a mistake defined table names and the foreign key id to be of type
'CHAR' (internally, really a VARCHAR).
The type should have been VARBINARY. */
trx->op_info = "creating foreign key sys tables"; const auto srv_file_per_table_backup= srv_file_per_table;
row_mysql_lock_data_dictionary(trx); /* We always want SYSTEM tables to be created inside the system
tablespace. */
srv_file_per_table= 0;
dberr_t error;
const char *tablename;
DBUG_EXECUTE_IF( if (!sys_foreign)
"create_and_drop_garbage", {
err = que_eval_sql( error= que_eval_sql(nullptr, "PROCEDURE CREATE_FOREIGN() IS\n"
NULL, "BEGIN\n"
"PROCEDURE CREATE_GARBAGE_TABLE_PROC () IS\n" "CREATE TABLE\n"
"BEGIN\n" "SYS_FOREIGN(ID CHAR, FOR_NAME CHAR,"
"CREATE TABLE\n" " REF_NAME CHAR, N_COLS INT);\n"
"\"test/" TEMP_FILE_PREFIX_INNODB "-garbage\"" "CREATE UNIQUE CLUSTERED INDEX ID_IND"
"(ID CHAR);\n" " ON SYS_FOREIGN (ID);\n"
"CREATE UNIQUE CLUSTERED INDEX PRIMARY ON " "CREATE INDEX FOR_IND"
"\"test/" TEMP_FILE_PREFIX_INNODB "-garbage\"(ID);\n" " ON SYS_FOREIGN (FOR_NAME);\n"
"END;\n", FALSE, trx); "CREATE INDEX REF_IND"
ut_ad(err == DB_SUCCESS); " ON SYS_FOREIGN (REF_NAME);\n"
row_drop_table_for_mysql("test/" "END;\n", false, trx);
TEMP_FILE_PREFIX_INNODB "-garbage", if (UNIV_UNLIKELY(error != DB_SUCCESS))
trx, SQLCOM_DROP_DB, true);); {
tablename= SYS_TABLE[SYS_FOREIGN].data();
err_exit:
ib::error() << "Creation of " << tablename << " failed: " << error;
trx->rollback();
row_mysql_unlock_data_dictionary(trx);
trx->free();
srv_file_per_table= srv_file_per_table_backup;
return error;
}
}
if (!sys_foreign_cols)
{
error= que_eval_sql(nullptr, "PROCEDURE CREATE_FOREIGN_COLS() IS\n"
"BEGIN\n"
"CREATE TABLE\n"
"SYS_FOREIGN_COLS(ID CHAR, POS INT,"
" FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
"CREATE UNIQUE CLUSTERED INDEX ID_IND"
" ON SYS_FOREIGN_COLS (ID, POS);\n"
"END;\n", false, trx);
if (UNIV_UNLIKELY(error != DB_SUCCESS))
{
tablename= SYS_TABLE[SYS_FOREIGN_COLS].data();
goto err_exit;
}
}
if (!sys_virtual)
{
error= que_eval_sql(nullptr, "PROCEDURE CREATE_VIRTUAL() IS\n"
"BEGIN\n"
"CREATE TABLE\n"
"SYS_VIRTUAL(TABLE_ID BIGINT,POS INT,BASE_POS INT);\n"
"CREATE UNIQUE CLUSTERED INDEX BASE_IDX"
" ON SYS_VIRTUAL(TABLE_ID, POS, BASE_POS);\n"
"END;\n", false, trx);
if (UNIV_UNLIKELY(error != DB_SUCCESS))
{
tablename= SYS_TABLE[SYS_VIRTUAL].data();
goto err_exit;
}
}
ib::info() << "Creating foreign key constraint system tables."; trx->commit();
row_mysql_unlock_data_dictionary(trx);
trx->free();
srv_file_per_table= srv_file_per_table_backup;
/* NOTE: in dict_load_foreigns we use the fact that mutex_lock();
there are 2 secondary indexes on SYS_FOREIGN, and they if (sys_foreign);
are defined just like below */ else if (!(sys_foreign= load_table(SYS_TABLE[SYS_FOREIGN])))
{
tablename= SYS_TABLE[SYS_FOREIGN].data();
load_fail:
mutex_unlock();
ib::error() << "Failed to CREATE TABLE " << tablename;
return DB_TABLE_NOT_FOUND;
}
else
prevent_eviction(sys_foreign);
/* NOTE: when designing InnoDB's foreign key support in 2001, we made if (sys_foreign_cols);
an error and made the table names and the foreign key id of type else if (!(sys_foreign_cols= load_table(SYS_TABLE[SYS_FOREIGN_COLS])))
'CHAR' (internally, really a VARCHAR). We should have made the type {
VARBINARY, like in other InnoDB system tables, to get a clean tablename= SYS_TABLE[SYS_FOREIGN_COLS].data();
design. */ goto load_fail;
}
else
prevent_eviction(sys_foreign_cols);
srv_file_per_table_backup = srv_file_per_table; if (sys_virtual);
else if (!(sys_virtual= load_table(SYS_TABLE[SYS_VIRTUAL])))
{
tablename= SYS_TABLE[SYS_VIRTUAL].data();
goto load_fail;
}
else
prevent_eviction(sys_virtual);
/* We always want SYSTEM tables to be created inside the system mutex_unlock();
tablespace. */ return DB_SUCCESS;
srv_file_per_table = 0;
err = que_eval_sql(
NULL,
"PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
"BEGIN\n"
"CREATE TABLE\n"
"SYS_FOREIGN(ID CHAR, FOR_NAME CHAR,"
" REF_NAME CHAR, N_COLS INT);\n"
"CREATE UNIQUE CLUSTERED INDEX ID_IND"
" ON SYS_FOREIGN (ID);\n"
"CREATE INDEX FOR_IND"
" ON SYS_FOREIGN (FOR_NAME);\n"
"CREATE INDEX REF_IND"
" ON SYS_FOREIGN (REF_NAME);\n"
"CREATE TABLE\n"
"SYS_FOREIGN_COLS(ID CHAR, POS INT,"
" FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
"CREATE UNIQUE CLUSTERED INDEX ID_IND"
" ON SYS_FOREIGN_COLS (ID, POS);\n"
"END;\n",
FALSE, trx);
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
ib::error() << "Creation of SYS_FOREIGN and SYS_FOREIGN_COLS"
" failed: " << err;
ut_ad(err == DB_OUT_OF_FILE_SPACE
|| err == DB_TOO_MANY_CONCURRENT_TRXS);
trx->rollback();
} else {
trx_commit_for_mysql(trx);
}
row_mysql_unlock_data_dictionary(trx);
trx->free();
srv_file_per_table = srv_file_per_table_backup;
/* Note: The master thread has not been started at this point. */
/* Confirm and move to the non-LRU part of the table LRU list. */
sys_foreign_err = dict_check_if_system_table_exists(
"SYS_FOREIGN", DICT_NUM_FIELDS__SYS_FOREIGN + 1, 3);
ut_a(sys_foreign_err == DB_SUCCESS);
sys_foreign_cols_err = dict_check_if_system_table_exists(
"SYS_FOREIGN_COLS", DICT_NUM_FIELDS__SYS_FOREIGN_COLS + 1, 1);
ut_a(sys_foreign_cols_err == DB_SUCCESS);
return(err);
}
/** Creates the virtual column system table (SYS_VIRTUAL) inside InnoDB
at server bootstrap or server start if the table is not found or is
not of the right form.
@return DB_SUCCESS or error code */
dberr_t
dict_create_or_check_sys_virtual()
{
trx_t* trx;
my_bool srv_file_per_table_backup;
dberr_t err;
ut_ad(!srv_any_background_activity());
err = dict_check_if_system_table_exists(
"SYS_VIRTUAL", DICT_NUM_FIELDS__SYS_VIRTUAL + 1, 1);
if (err == DB_SUCCESS) {
dict_sys.mutex_lock();
dict_sys.sys_virtual = dict_table_get_low("SYS_VIRTUAL");
dict_sys.mutex_unlock();
return(DB_SUCCESS);
}
if (srv_read_only_mode
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO) {
return(DB_READ_ONLY);
}
trx = trx_create();
trx->dict_operation = true;
trx->op_info = "creating sys_virtual tables";
row_mysql_lock_data_dictionary(trx);
ib::info() << "Creating sys_virtual system tables.";
srv_file_per_table_backup = srv_file_per_table;
/* We always want SYSTEM tables to be created inside the system
tablespace. */
srv_file_per_table = 0;
err = que_eval_sql(
NULL,
"PROCEDURE CREATE_SYS_VIRTUAL_TABLES_PROC () IS\n"
"BEGIN\n"
"CREATE TABLE\n"
"SYS_VIRTUAL(TABLE_ID BIGINT, POS INT,"
" BASE_POS INT);\n"
"CREATE UNIQUE CLUSTERED INDEX BASE_IDX"
" ON SYS_VIRTUAL(TABLE_ID, POS, BASE_POS);\n"
"END;\n",
FALSE, trx);
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
ib::error() << "Creation of SYS_VIRTUAL failed: " << err;
ut_ad(err == DB_OUT_OF_FILE_SPACE
|| err == DB_TOO_MANY_CONCURRENT_TRXS);
trx->rollback();
} else {
trx_commit_for_mysql(trx);
}
row_mysql_unlock_data_dictionary(trx);
trx->free();
srv_file_per_table = srv_file_per_table_backup;
/* Note: The master thread has not been started at this point. */
/* Confirm and move to the non-LRU part of the table LRU list. */
dberr_t sys_virtual_err = dict_check_if_system_table_exists(
"SYS_VIRTUAL", DICT_NUM_FIELDS__SYS_VIRTUAL + 1, 1);
ut_a(sys_virtual_err == DB_SUCCESS);
dict_sys.mutex_lock();
dict_sys.sys_virtual = dict_table_get_low("SYS_VIRTUAL");
dict_sys.mutex_unlock();
return(err);
} }
/****************************************************************//** /****************************************************************//**
@@ -1959,35 +1907,19 @@ dict_create_add_foreigns_to_dictionary(
const dict_table_t* table, const dict_table_t* table,
trx_t* trx) trx_t* trx)
{ {
dict_foreign_t* foreign; dict_sys.assert_locked();
dberr_t error;
dict_sys.assert_locked(); if (!dict_sys.sys_foreign)
{
sql_print_error("InnoDB: Table SYS_FOREIGN not found"
" in internal data dictionary");
return DB_ERROR;
}
if (NULL == dict_table_get_low("SYS_FOREIGN")) { for (auto fk : local_fk_set)
if (dberr_t error=
dict_create_add_foreign_to_dictionary(table->name.m_name, fk, trx))
return error;
ib::error() << "Table SYS_FOREIGN not found" return DB_SUCCESS;
" in internal data dictionary";
return(DB_ERROR);
}
error = DB_SUCCESS;
for (dict_foreign_set::const_iterator it = local_fk_set.begin();
it != local_fk_set.end();
++it) {
foreign = *it;
ut_ad(foreign->id != NULL);
error = dict_create_add_foreign_to_dictionary(
table->name.m_name, foreign, trx);
if (error != DB_SUCCESS) {
break;
}
}
return error;
} }

View File

@@ -51,9 +51,9 @@ extern uint ibuf_debug;
#include "buf0buf.h" #include "buf0buf.h"
#include "data0type.h" #include "data0type.h"
#include "dict0boot.h" #include "dict0boot.h"
#include "dict0load.h"
#include "dict0crea.h" #include "dict0crea.h"
#include "dict0mem.h" #include "dict0mem.h"
#include "dict0priv.h"
#include "dict0stats.h" #include "dict0stats.h"
#include "fts0fts.h" #include "fts0fts.h"
#include "fts0types.h" #include "fts0types.h"
@@ -80,6 +80,15 @@ extern uint ibuf_debug;
/** the dictionary system */ /** the dictionary system */
dict_sys_t dict_sys; dict_sys_t dict_sys;
/** System table names; @see dict_system_id_t */
const span<const char> dict_sys_t::SYS_TABLE[]=
{
{C_STRING_WITH_LEN("SYS_TABLES")},{C_STRING_WITH_LEN("SYS_INDEXES")},
{C_STRING_WITH_LEN("SYS_COLUMNS")},{C_STRING_WITH_LEN("SYS_FIELDS")},
{C_STRING_WITH_LEN("SYS_FOREIGN")},{C_STRING_WITH_LEN("SYS_FOREIGN_COLS")},
{C_STRING_WITH_LEN("SYS_VIRTUAL")}
};
/** Diagnostic message for exceeding the mutex_lock_wait() timeout */ /** Diagnostic message for exceeding the mutex_lock_wait() timeout */
const char dict_sys_t::fatal_msg[]= const char dict_sys_t::fatal_msg[]=
"innodb_fatal_semaphore_wait_threshold was exceeded for dict_sys.mutex. " "innodb_fatal_semaphore_wait_threshold was exceeded for dict_sys.mutex. "
@@ -216,7 +225,7 @@ static dict_table_t* dict_table_open_on_id_low(
dict_err_ignore_t ignore_err, dict_err_ignore_t ignore_err,
bool cached_only) bool cached_only)
{ {
dict_table_t* table = dict_sys.get_table(table_id); dict_table_t* table = dict_sys.find_table(table_id);
if (!table && !cached_only) { if (!table && !cached_only) {
table = dict_load_table_on_id(table_id, ignore_err); table = dict_load_table_on_id(table_id, ignore_err);
@@ -1097,17 +1106,11 @@ dict_table_open_on_name(
} }
ut_ad(table_name); ut_ad(table_name);
dict_sys.assert_locked(); table = dict_sys.load_table({table_name, strlen(table_name)},
ignore_err);
table = dict_table_check_if_in_cache_low(table_name); if (table) {
ut_ad(table->cached);
if (table == NULL) {
table = dict_load_table(table_name, ignore_err);
}
ut_ad(!table || table->cached);
if (table != NULL) {
/* If table is encrypted or corrupted */ /* If table is encrypted or corrupted */
if (!(ignore_err & ~DICT_ERR_IGNORE_FK_NOKEY) if (!(ignore_err & ~DICT_ERR_IGNORE_FK_NOKEY)
@@ -2984,11 +2987,13 @@ dict_foreign_add_to_cache(
dict_sys.assert_locked(); dict_sys.assert_locked();
for_table = dict_table_check_if_in_cache_low( for_table = dict_sys.find_table(
foreign->foreign_table_name_lookup); {foreign->foreign_table_name_lookup,
strlen(foreign->foreign_table_name_lookup)});
ref_table = dict_table_check_if_in_cache_low( ref_table = dict_sys.find_table(
foreign->referenced_table_name_lookup); {foreign->referenced_table_name_lookup,
strlen(foreign->referenced_table_name_lookup)});
ut_a(for_table || ref_table); ut_a(for_table || ref_table);
if (for_table) { if (for_table) {
@@ -3384,8 +3389,8 @@ dict_get_referenced_table(
} }
/* Copy database_name, '/', table_name, '\0' */ /* Copy database_name, '/', table_name, '\0' */
ref = static_cast<char*>(mem_heap_alloc( const size_t len = database_name_len + table_name_len + 1;
heap, database_name_len + table_name_len + 2)); ref = static_cast<char*>(mem_heap_alloc(heap, len + 1));
memcpy(ref, database_name, database_name_len); memcpy(ref, database_name, database_name_len);
ref[database_name_len] = '/'; ref[database_name_len] = '/';
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1); memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
@@ -3395,7 +3400,7 @@ dict_get_referenced_table(
2 = Store as given, compare in lower; case semi-sensitive */ 2 = Store as given, compare in lower; case semi-sensitive */
if (lower_case_table_names == 2) { if (lower_case_table_names == 2) {
innobase_casedn_str(ref); innobase_casedn_str(ref);
*table = dict_table_get_low(ref); *table = dict_sys.load_table({ref, len});
memcpy(ref, database_name, database_name_len); memcpy(ref, database_name, database_name_len);
ref[database_name_len] = '/'; ref[database_name_len] = '/';
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1); memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
@@ -3408,7 +3413,7 @@ dict_get_referenced_table(
#else #else
innobase_casedn_str(ref); innobase_casedn_str(ref);
#endif /* !_WIN32 */ #endif /* !_WIN32 */
*table = dict_table_get_low(ref); *table = dict_sys.load_table({ref, len});
} }
return(ref); return(ref);
@@ -5031,9 +5036,3 @@ dict_tf_to_row_format_string(
ut_error; ut_error;
return(0); return(0);
} }
bool dict_table_t::is_stats_table() const
{
return !strcmp(name.m_name, TABLE_STATS_NAME) ||
!strcmp(name.m_name, INDEX_STATS_NAME);
}

View File

@@ -27,14 +27,13 @@ Created 4/24/1996 Heikki Tuuri
#include "dict0load.h" #include "dict0load.h"
#include "mysql_version.h" #include "log.h"
#include "btr0pcur.h" #include "btr0pcur.h"
#include "btr0btr.h" #include "btr0btr.h"
#include "dict0boot.h" #include "dict0boot.h"
#include "dict0crea.h" #include "dict0crea.h"
#include "dict0dict.h" #include "dict0dict.h"
#include "dict0mem.h" #include "dict0mem.h"
#include "dict0priv.h"
#include "dict0stats.h" #include "dict0stats.h"
#include "fsp0file.h" #include "fsp0file.h"
#include "fts0priv.h" #include "fts0priv.h"
@@ -45,18 +44,6 @@ Created 4/24/1996 Heikki Tuuri
#include "srv0srv.h" #include "srv0srv.h"
#include "fts0opt.h" #include "fts0opt.h"
/** Following are the InnoDB system tables. The positions in
this array are referenced by enum dict_system_table_id. */
static const char* SYSTEM_TABLE_NAME[] = {
"SYS_TABLES",
"SYS_INDEXES",
"SYS_COLUMNS",
"SYS_FIELDS",
"SYS_FOREIGN",
"SYS_FOREIGN_COLS",
"SYS_VIRTUAL"
};
/** Loads a table definition and also all its index definitions. /** Loads a table definition and also all its index definitions.
Loads those foreign key constraints whose referenced table is already in Loads those foreign key constraints whose referenced table is already in
@@ -71,26 +58,11 @@ key constraints are loaded into memory.
@param[out] fk_tables Related table names that must also be @param[out] fk_tables Related table names that must also be
loaded to ensure that all foreign key loaded to ensure that all foreign key
constraints are loaded. constraints are loaded.
@return table, NULL if does not exist; if the table is stored in an @return table, possibly with file_unreadable flag set
.ibd file, but the file does not exist, then we set the @retval nullptr if the table does not exist */
file_unreadable flag in the table object we return */ static dict_table_t *dict_load_table_one(const span<const char> &name,
static dict_err_ignore_t ignore_err,
dict_table_t* dict_names_t &fk_tables);
dict_load_table_one(
const table_name_t& name,
dict_err_ignore_t ignore_err,
dict_names_t& fk_tables);
/** Load a table definition from a SYS_TABLES record to dict_table_t.
Do not load any columns or indexes.
@param[in] name Table name
@param[in] rec SYS_TABLES record
@param[out,own] table table, or NULL
@return error message
@retval NULL on success */
static const char* dict_load_table_low(const table_name_t& name,
const rec_t* rec, dict_table_t** table)
MY_ATTRIBUTE((nonnull, warn_unused_result));
/** Load an index definition from a SYS_INDEXES record to dict_index_t. /** Load an index definition from a SYS_INDEXES record to dict_index_t.
If allocate=TRUE, we will create a dict_index_t structure and fill it If allocate=TRUE, we will create a dict_index_t structure and fill it
@@ -239,24 +211,11 @@ dict_startscan_system(
btr_pcur_t* pcur, /*!< out: persistent cursor to btr_pcur_t* pcur, /*!< out: persistent cursor to
the record */ the record */
mtr_t* mtr, /*!< in: the mini-transaction */ mtr_t* mtr, /*!< in: the mini-transaction */
dict_system_id_t system_id) /*!< in: which system table to open */ dict_table_t* table) /*!< in: system table */
{ {
dict_table_t* system_table; btr_pcur_open_at_index_side(true, table->indexes.start,
dict_index_t* clust_index; BTR_SEARCH_LEAF, pcur, true, 0, mtr);
const rec_t* rec; return dict_getnext_system_low(pcur, mtr);
ut_a(system_id < SYS_NUM_SYSTEM_TABLES);
system_table = dict_table_get_low(SYSTEM_TABLE_NAME[system_id]);
clust_index = UT_LIST_GET_FIRST(system_table->indexes);
btr_pcur_open_at_index_side(true, clust_index, BTR_SEARCH_LEAF, pcur,
true, 0, mtr);
rec = dict_getnext_system_low(pcur, mtr);
return(rec);
} }
/********************************************************************//** /********************************************************************//**
@@ -280,46 +239,6 @@ dict_getnext_system(
return(rec); return(rec);
} }
/********************************************************************//**
This function processes one SYS_TABLES record and populate the dict_table_t
struct for the table.
@return error message, or NULL on success */
const char*
dict_process_sys_tables_rec_and_mtr_commit(
/*=======================================*/
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 */
bool cached, /*!< in: whether to load from cache */
mtr_t* mtr) /*!< in/out: mini-transaction,
will be committed */
{
ulint len;
const char* field;
field = (const char*) rec_get_nth_field_old(
rec, DICT_FLD__SYS_TABLES__NAME, &len);
ut_a(!rec_get_deleted_flag(rec, 0));
ut_ad(mtr->memo_contains_page_flagged(rec, MTR_MEMO_PAGE_S_FIX));
/* Get the table name */
table_name_t table_name(mem_heap_strdupl(heap, field, len));
if (cached) {
/* Commit before load the table again */
mtr_commit(mtr);
*table = dict_table_get_low(table_name.m_name);
return *table ? NULL : "Table not found in cache";
} else {
const char* err = dict_load_table_low(table_name, rec, table);
mtr_commit(mtr);
return err;
}
}
/********************************************************************//** /********************************************************************//**
This function parses a SYS_INDEXES record and populate a dict_index_t This function parses a SYS_INDEXES record and populate a dict_index_t
structure with the information from the record. For detail information structure with the information from the record. For detail information
@@ -724,7 +643,7 @@ dict_sys_tables_type_to_tf(ulint type, bool not_redundant)
/** Read and return 5 integer fields from a SYS_TABLES record. /** Read and return 5 integer fields from a SYS_TABLES record.
@param[in] rec A record of SYS_TABLES @param[in] rec A record of SYS_TABLES
@param[in] name Table Name, the same as SYS_TABLES.NAME @param[in] name SYS_TABLES.NAME
@param[out] table_id Pointer to the table_id for this table @param[out] table_id Pointer to the table_id for this table
@param[out] space_id Pointer to the space_id for this table @param[out] space_id Pointer to the space_id for this table
@param[out] n_cols Pointer to number of columns for this table. @param[out] n_cols Pointer to number of columns for this table.
@@ -736,7 +655,7 @@ static
bool bool
dict_sys_tables_rec_read( dict_sys_tables_rec_read(
const rec_t* rec, const rec_t* rec,
const table_name_t& table_name, const span<const char>& name,
table_id_t* table_id, table_id_t* table_id,
ulint* space_id, ulint* space_id,
ulint* n_cols, ulint* n_cols,
@@ -850,10 +769,11 @@ dict_sys_tables_rec_read(
const bool not_redundant = 0 != (*n_cols & DICT_N_COLS_COMPACT); const bool not_redundant = 0 != (*n_cols & DICT_N_COLS_COMPACT);
if (!dict_sys_tables_type_valid(type, not_redundant)) { if (!dict_sys_tables_type_valid(type, not_redundant)) {
ib::error() << "Table " << table_name << " in InnoDB" sql_print_error("InnoDB: Table %.*s in InnoDB"
" data dictionary contains invalid flags." " data dictionary contains invalid flags."
" SYS_TABLES.TYPE=" << type << " SYS_TABLES.TYPE=" ULINTPF
" SYS_TABLES.N_COLS=" << *n_cols; " SYS_TABLES.N_COLS=" ULINTPF,
name.size(), name.data(), type, *n_cols);
return(false); return(false);
} }
@@ -873,10 +793,13 @@ dict_sys_tables_rec_read(
*flags2 = mach_read_from_4(field); *flags2 = mach_read_from_4(field);
if (!dict_tf2_is_valid(*flags, *flags2)) { if (!dict_tf2_is_valid(*flags, *flags2)) {
ib::error() << "Table " << table_name << " in InnoDB" sql_print_error("InnoDB: Table %.*s in InnoDB"
" data dictionary contains invalid flags." " data dictionary"
" SYS_TABLES.TYPE=" << type " contains invalid flags."
<< " SYS_TABLES.MIX_LEN=" << *flags2; " SYS_TABLES.TYPE=" ULINTPF
" SYS_TABLES.MIX_LEN=" ULINTPF,
name.size(), name.data(),
type, *flags2);
return(false); return(false);
} }
@@ -901,7 +824,6 @@ static ulint dict_check_sys_tables()
{ {
ulint max_space_id = 0; ulint max_space_id = 0;
btr_pcur_t pcur; btr_pcur_t pcur;
const rec_t* rec;
mtr_t mtr; mtr_t mtr;
DBUG_ENTER("dict_check_sys_tables"); DBUG_ENTER("dict_check_sys_tables");
@@ -910,11 +832,9 @@ static ulint dict_check_sys_tables()
mtr_start(&mtr); mtr_start(&mtr);
for (rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES); for (const rec_t *rec = dict_startscan_system(&pcur, &mtr,
rec != NULL; dict_sys.sys_tables);
mtr.commit(), mtr.start(), rec; rec = dict_getnext_system(&pcur, &mtr)) {
rec = dict_getnext_system(&pcur, &mtr)) {
const byte* field;
ulint len; ulint len;
table_id_t table_id; table_id_t table_id;
ulint space_id; ulint space_id;
@@ -924,39 +844,40 @@ static ulint dict_check_sys_tables()
/* If a table record is not useable, ignore it and continue /* If a table record is not useable, ignore it and continue
on to the next record. Error messages were logged. */ on to the next record. Error messages were logged. */
if (dict_sys_tables_rec_check(rec) != NULL) { if (dict_sys_tables_rec_check(rec)) {
continue; continue;
} }
/* Copy the table name from rec */ /* Copy the table name from rec */
field = rec_get_nth_field_old( const char *field = reinterpret_cast<const char*>(
rec, DICT_FLD__SYS_TABLES__NAME, &len); rec_get_nth_field_old(rec, DICT_FLD__SYS_TABLES__NAME,
&len));
table_name_t table_name(mem_strdupl((char*) field, len)); if (len == UNIV_SQL_NULL
DBUG_PRINT("dict_check_sys_tables", || dict_table_t::is_garbage_name(field, len)) {
("name: %p, '%s'", table_name.m_name, /* This table will be dropped by
table_name.m_name)); dict_table_t::drop_garbage().
We do not care if the file exists. */
if (!dict_sys_tables_rec_read(rec, table_name,
&table_id, &space_id,
&n_cols, &flags, &flags2)
|| space_id == TRX_SYS_SPACE) {
next:
ut_free(table_name.m_name);
continue; continue;
} }
if (strstr(table_name.m_name, "/" TEMP_FILE_PREFIX_INNODB)) { DBUG_PRINT("dict_check_sys_tables",
/* This table will be dropped by ("name: %*.s", static_cast<int>(len), field));
row_mysql_drop_garbage_tables().
We do not care if the file exists. */ const span<const char> name{field, len};
goto next;
if (!dict_sys_tables_rec_read(rec, name, &table_id, &space_id,
&n_cols, &flags, &flags2)
|| space_id == TRX_SYS_SPACE) {
continue;
} }
if (flags2 & DICT_TF2_DISCARDED) { if (flags2 & DICT_TF2_DISCARDED) {
ib::info() << "Ignoring tablespace for " << table_name sql_print_information("InnoDB: Ignoring tablespace"
<< " because the DISCARD flag is set ."; " for %.*s because "
goto next; "the DISCARD flag is set",
static_cast<int>(len), field);
continue;
} }
/* For tables or partitions using .ibd files, the flag /* For tables or partitions using .ibd files, the flag
@@ -968,10 +889,10 @@ next:
will otherwise ignore the flag. */ will otherwise ignore the flag. */
if (fil_space_for_table_exists_in_mem(space_id, flags)) { if (fil_space_for_table_exists_in_mem(space_id, flags)) {
goto next; continue;
} }
char* filepath = fil_make_filepath(nullptr, table_name, char* filepath = fil_make_filepath(nullptr, name,
IBD, false); IBD, false);
/* Check that the .ibd file exists. */ /* Check that the .ibd file exists. */
@@ -979,16 +900,17 @@ next:
false, false,
FIL_TYPE_TABLESPACE, FIL_TYPE_TABLESPACE,
space_id, dict_tf_to_fsp_flags(flags), space_id, dict_tf_to_fsp_flags(flags),
table_name, filepath)) { name, filepath)) {
ib::warn() << "Ignoring tablespace for " sql_print_warning("InnoDB: Ignoring tablespace for"
<< table_name " %.*s because it"
<< " because it could not be opened."; " could not be opened.",
static_cast<int>(name.size()),
name.data());
} }
max_space_id = ut_max(max_space_id, space_id); max_space_id = ut_max(max_space_id, space_id);
ut_free(filepath); ut_free(filepath);
goto next;
} }
mtr_commit(&mtr); mtr_commit(&mtr);
@@ -1307,8 +1229,6 @@ dict_load_columns(
mem_heap_t* heap) /*!< in/out: memory heap mem_heap_t* heap) /*!< in/out: memory heap
for temporary storage */ for temporary storage */
{ {
dict_table_t* sys_columns;
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;
@@ -1322,13 +1242,12 @@ dict_load_columns(
mtr_start(&mtr); mtr_start(&mtr);
sys_columns = dict_table_get_low("SYS_COLUMNS"); dict_index_t* sys_index = dict_sys.sys_columns->indexes.start;
sys_index = UT_LIST_GET_FIRST(sys_columns->indexes); ut_ad(!dict_sys.sys_columns->not_redundant());
ut_ad(!dict_table_is_comp(sys_columns));
ut_ad(name_of_col_is(sys_columns, sys_index, ut_ad(name_of_col_is(dict_sys.sys_columns, sys_index,
DICT_FLD__SYS_COLUMNS__NAME, "NAME")); DICT_FLD__SYS_COLUMNS__NAME, "NAME"));
ut_ad(name_of_col_is(sys_columns, sys_index, ut_ad(name_of_col_is(dict_sys.sys_columns, sys_index,
DICT_FLD__SYS_COLUMNS__PREC, "PREC")); DICT_FLD__SYS_COLUMNS__PREC, "PREC"));
tuple = dtuple_create(heap, 1); tuple = dtuple_create(heap, 1);
@@ -1423,7 +1342,6 @@ dict_load_virtual_one_col(
dict_v_col_t* v_col, dict_v_col_t* v_col,
mem_heap_t* heap) mem_heap_t* heap)
{ {
dict_table_t* sys_virtual;
dict_index_t* sys_virtual_index; dict_index_t* sys_virtual_index;
btr_pcur_t pcur; btr_pcur_t pcur;
dtuple_t* tuple; dtuple_t* tuple;
@@ -1442,11 +1360,10 @@ dict_load_virtual_one_col(
mtr_start(&mtr); mtr_start(&mtr);
sys_virtual = dict_table_get_low("SYS_VIRTUAL"); sys_virtual_index = dict_sys.sys_virtual->indexes.start;
sys_virtual_index = UT_LIST_GET_FIRST(sys_virtual->indexes); ut_ad(!dict_sys.sys_virtual->not_redundant());
ut_ad(!dict_table_is_comp(sys_virtual));
ut_ad(name_of_col_is(sys_virtual, sys_virtual_index, ut_ad(name_of_col_is(dict_sys.sys_virtual, sys_virtual_index,
DICT_FLD__SYS_VIRTUAL__POS, "POS")); DICT_FLD__SYS_VIRTUAL__POS, "POS"));
tuple = dtuple_create(heap, 2); tuple = dtuple_create(heap, 2);
@@ -1656,8 +1573,6 @@ dict_load_fields(
dict_index_t* index, /*!< in/out: index whose fields to load */ dict_index_t* index, /*!< in/out: index whose fields to load */
mem_heap_t* heap) /*!< in: memory heap for temporary storage */ mem_heap_t* heap) /*!< in: memory heap for temporary storage */
{ {
dict_table_t* sys_fields;
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;
@@ -1671,10 +1586,9 @@ dict_load_fields(
mtr_start(&mtr); mtr_start(&mtr);
sys_fields = dict_table_get_low("SYS_FIELDS"); dict_index_t* sys_index = dict_sys.sys_fields->indexes.start;
sys_index = UT_LIST_GET_FIRST(sys_fields->indexes); ut_ad(!dict_sys.sys_fields->not_redundant());
ut_ad(!dict_table_is_comp(sys_fields)); ut_ad(name_of_col_is(dict_sys.sys_fields, sys_index,
ut_ad(name_of_col_is(sys_fields, sys_index,
DICT_FLD__SYS_FIELDS__COL_NAME, "COL_NAME")); DICT_FLD__SYS_FIELDS__COL_NAME, "COL_NAME"));
tuple = dtuple_create(heap, 1); tuple = dtuple_create(heap, 1);
@@ -1889,7 +1803,6 @@ dict_load_indexes(
/*!< in: error to be ignored when /*!< in: error to be ignored when
loading the index definition */ loading the index definition */
{ {
dict_table_t* sys_indexes;
dict_index_t* sys_index; dict_index_t* sys_index;
btr_pcur_t pcur; btr_pcur_t pcur;
dtuple_t* tuple; dtuple_t* tuple;
@@ -1903,12 +1816,11 @@ dict_load_indexes(
mtr_start(&mtr); mtr_start(&mtr);
sys_indexes = dict_table_get_low("SYS_INDEXES"); sys_index = dict_sys.sys_indexes->indexes.start;
sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes); ut_ad(!dict_sys.sys_indexes->not_redundant());
ut_ad(!dict_table_is_comp(sys_indexes)); ut_ad(name_of_col_is(dict_sys.sys_indexes, sys_index,
ut_ad(name_of_col_is(sys_indexes, sys_index,
DICT_FLD__SYS_INDEXES__NAME, "NAME")); DICT_FLD__SYS_INDEXES__NAME, "NAME"));
ut_ad(name_of_col_is(sys_indexes, sys_index, ut_ad(name_of_col_is(dict_sys.sys_indexes, sys_index,
DICT_FLD__SYS_INDEXES__PAGE_NO, "PAGE_NO")); DICT_FLD__SYS_INDEXES__PAGE_NO, "PAGE_NO"));
tuple = dtuple_create(heap, 1); tuple = dtuple_create(heap, 1);
@@ -2156,11 +2068,11 @@ func_exit:
Do not load any columns or indexes. Do not load any columns or indexes.
@param[in] name Table name @param[in] name Table name
@param[in] rec SYS_TABLES record @param[in] rec SYS_TABLES record
@param[out,own] table table, or NULL @param[out,own] table table, or nullptr
@return error message @return error message
@retval NULL on success */ @retval nullptr on success */
static const char* dict_load_table_low(const table_name_t& name, const char *dict_load_table_low(const span<const char> &name,
const rec_t* rec, dict_table_t** table) const rec_t *rec, dict_table_t **table)
{ {
table_id_t table_id; table_id_t table_id;
ulint space_id; ulint space_id;
@@ -2183,8 +2095,8 @@ static const char* dict_load_table_low(const table_name_t& name,
dict_table_decode_n_col(t_num, &n_cols, &n_v_col); dict_table_decode_n_col(t_num, &n_cols, &n_v_col);
*table = dict_mem_table_create( *table = dict_table_t::create(name, nullptr, n_cols + n_v_col,
name.m_name, NULL, n_cols + n_v_col, n_v_col, flags, flags2); n_v_col, flags, flags2);
(*table)->space_id = space_id; (*table)->space_id = space_id;
(*table)->id = table_id; (*table)->id = table_id;
(*table)->file_unreadable = !!(flags2 & DICT_TF2_DISCARDED); (*table)->file_unreadable = !!(flags2 & DICT_TF2_DISCARDED);
@@ -2271,44 +2183,6 @@ dict_get_and_save_data_dir_path(
} }
} }
/** 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.
@param[in] name Table name in the dbname/tablename format
@param[in] ignore_err Error to be ignored when loading
table and its index definition
@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 file_unreadable
flag in the table object we return. */
dict_table_t* dict_load_table(const char* name, dict_err_ignore_t ignore_err)
{
dict_names_t fk_list;
dict_table_t* result;
dict_names_t::iterator i;
DBUG_ENTER("dict_load_table");
DBUG_PRINT("dict_load_table", ("loading table: '%s'", name));
dict_sys.assert_locked();
result = dict_table_check_if_in_cache_low(name);
if (!result) {
result = dict_load_table_one(const_cast<char*>(name),
ignore_err, fk_list);
while (!fk_list.empty()) {
if (!dict_table_check_if_in_cache_low(fk_list.front()))
dict_load_table_one(
const_cast<char*>(fk_list.front()),
ignore_err, fk_list);
fk_list.pop_front();
}
}
DBUG_RETURN(result);
}
/** Opens a tablespace for dict_load_table_one() /** Opens a tablespace for dict_load_table_one()
@param[in,out] table A table that refers to the tablespace to open @param[in,out] table A table that refers to the tablespace to open
@param[in] ignore_err Whether to ignore an error. */ @param[in] ignore_err Whether to ignore an error. */
@@ -2368,12 +2242,10 @@ dict_load_tablespace(
} }
} }
/* Try to open the tablespace. We set the 2nd param (fix_dict) to
false because we do not have an x-lock on dict_sys.latch */
table->space = fil_ibd_open( table->space = fil_ibd_open(
true, FIL_TYPE_TABLESPACE, table->space_id, true, FIL_TYPE_TABLESPACE, table->space_id,
dict_tf_to_fsp_flags(table->flags), dict_tf_to_fsp_flags(table->flags),
table->name, filepath); {table->name.m_name, strlen(table->name.m_name)}, filepath);
if (!table->space) { if (!table->space) {
/* We failed to find a sensible tablespace file */ /* We failed to find a sensible tablespace file */
@@ -2397,20 +2269,14 @@ key constraints are loaded into memory.
@param[out] fk_tables Related table names that must also be @param[out] fk_tables Related table names that must also be
loaded to ensure that all foreign key loaded to ensure that all foreign key
constraints are loaded. constraints are loaded.
@return table, NULL if does not exist; if the table is stored in an @return table, possibly with file_unreadable flag set
.ibd file, but the file does not exist, then we set the @retval nullptr if the table does not exist */
file_unreadable flag in the table object we return */ static dict_table_t *dict_load_table_one(const span<const char> &name,
static dict_err_ignore_t ignore_err,
dict_table_t* dict_names_t &fk_tables)
dict_load_table_one(
const table_name_t& name,
dict_err_ignore_t ignore_err,
dict_names_t& fk_tables)
{ {
dberr_t err; dberr_t err;
dict_table_t* sys_tables;
btr_pcur_t pcur; btr_pcur_t pcur;
dict_index_t* sys_index;
dtuple_t* tuple; dtuple_t* tuple;
mem_heap_t* heap; mem_heap_t* heap;
dfield_t* dfield; dfield_t* dfield;
@@ -2420,7 +2286,8 @@ dict_load_table_one(
mtr_t mtr; mtr_t mtr;
DBUG_ENTER("dict_load_table_one"); DBUG_ENTER("dict_load_table_one");
DBUG_PRINT("dict_load_table_one", ("table: %s", name.m_name)); DBUG_PRINT("dict_load_table_one",
("table: %.*s", name.size(), name.data()));
dict_sys.assert_locked(); dict_sys.assert_locked();
@@ -2428,24 +2295,23 @@ dict_load_table_one(
mtr_start(&mtr); mtr_start(&mtr);
sys_tables = dict_table_get_low("SYS_TABLES"); dict_index_t *sys_index = dict_sys.sys_tables->indexes.start;
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); ut_ad(!dict_sys.sys_tables->not_redundant());
ut_ad(!dict_table_is_comp(sys_tables)); ut_ad(name_of_col_is(dict_sys.sys_tables, sys_index,
ut_ad(name_of_col_is(sys_tables, sys_index,
DICT_FLD__SYS_TABLES__ID, "ID")); DICT_FLD__SYS_TABLES__ID, "ID"));
ut_ad(name_of_col_is(sys_tables, sys_index, ut_ad(name_of_col_is(dict_sys.sys_tables, sys_index,
DICT_FLD__SYS_TABLES__N_COLS, "N_COLS")); DICT_FLD__SYS_TABLES__N_COLS, "N_COLS"));
ut_ad(name_of_col_is(sys_tables, sys_index, ut_ad(name_of_col_is(dict_sys.sys_tables, sys_index,
DICT_FLD__SYS_TABLES__TYPE, "TYPE")); DICT_FLD__SYS_TABLES__TYPE, "TYPE"));
ut_ad(name_of_col_is(sys_tables, sys_index, ut_ad(name_of_col_is(dict_sys.sys_tables, sys_index,
DICT_FLD__SYS_TABLES__MIX_LEN, "MIX_LEN")); DICT_FLD__SYS_TABLES__MIX_LEN, "MIX_LEN"));
ut_ad(name_of_col_is(sys_tables, sys_index, ut_ad(name_of_col_is(dict_sys.sys_tables, sys_index,
DICT_FLD__SYS_TABLES__SPACE, "SPACE")); DICT_FLD__SYS_TABLES__SPACE, "SPACE"));
tuple = dtuple_create(heap, 1); tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0); dfield = dtuple_get_nth_field(tuple, 0);
dfield_set_data(dfield, name.m_name, strlen(name.m_name)); dfield_set_data(dfield, name.data(), name.size());
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,
@@ -2467,9 +2333,7 @@ err_exit:
rec, DICT_FLD__SYS_TABLES__NAME, &len); rec, DICT_FLD__SYS_TABLES__NAME, &len);
/* Check if the table name in record is the searched one */ /* Check if the table name in record is the searched one */
if (len != strlen(name.m_name) if (len != name.size() || memcmp(name.data(), field, len)) {
|| memcmp(name.m_name, field, len)) {
goto err_exit; goto err_exit;
} }
@@ -2645,6 +2509,25 @@ func_exit:
DBUG_RETURN(table); DBUG_RETURN(table);
} }
dict_table_t *dict_sys_t::load_table(const span<const char> &name,
dict_err_ignore_t ignore)
{
if (dict_table_t *table= find_table(name))
return table;
dict_names_t fk_list;
dict_table_t *table= dict_load_table_one(name, ignore, fk_list);
while (!fk_list.empty())
{
const char *f= fk_list.front();
const span<const char> name{f, strlen(f)};
if (!find_table(name))
dict_load_table_one(name, ignore, fk_list);
fk_list.pop_front();
}
return table;
}
/***********************************************************************//** /***********************************************************************//**
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 */
@@ -2657,48 +2540,41 @@ dict_load_table_on_id(
{ {
byte id_buf[8]; byte id_buf[8];
btr_pcur_t pcur; btr_pcur_t pcur;
mem_heap_t* heap;
dtuple_t* tuple;
dfield_t* dfield;
dict_index_t* sys_table_ids;
dict_table_t* sys_tables;
const rec_t* rec;
const byte* field; const byte* field;
ulint len; ulint len;
dict_table_t* table;
mtr_t mtr; mtr_t mtr;
dict_sys.assert_locked(); dict_sys.assert_locked();
table = NULL;
/* NOTE that the operation of this function is protected by /* NOTE that the operation of this function is protected by
the dictionary mutex, and therefore no deadlocks can occur the dictionary mutex, and therefore no deadlocks can occur
with other dictionary operations. */ with other dictionary operations. */
mtr_start(&mtr); mtr.start();
/*---------------------------------------------------*/ /*---------------------------------------------------*/
/* Get the secondary index based on ID for table SYS_TABLES */ /* Get the secondary index based on ID for table SYS_TABLES */
sys_tables = dict_sys.sys_tables; dict_index_t *sys_table_ids =
sys_table_ids = dict_table_get_next_index( dict_sys.sys_tables->indexes.start->indexes.next;
dict_table_get_first_index(sys_tables));
ut_ad(!dict_table_is_comp(sys_tables));
ut_ad(!dict_index_is_clust(sys_table_ids));
heap = mem_heap_create(256);
tuple = dtuple_create(heap, 1); dfield_t dfield;
dfield = dtuple_get_nth_field(tuple, 0); dtuple_t tuple{
0,1,1,&dfield,0,nullptr
#ifdef UNIV_DEBUG
, DATA_TUPLE_MAGIC_N
#endif
};
/* Write the table id in byte format to id_buf */ /* Write the table id in byte format to id_buf */
mach_write_to_8(id_buf, table_id); mach_write_to_8(id_buf, table_id);
dfield_set_data(&dfield, id_buf, 8);
dict_index_copy_types(&tuple, sys_table_ids, 1);
dfield_set_data(dfield, id_buf, 8); btr_pcur_open_on_user_rec(sys_table_ids, &tuple, PAGE_CUR_GE,
dict_index_copy_types(tuple, sys_table_ids, 1);
btr_pcur_open_on_user_rec(sys_table_ids, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr); BTR_SEARCH_LEAF, &pcur, &mtr);
rec = btr_pcur_get_rec(&pcur);
const rec_t* rec = btr_pcur_get_rec(&pcur);
dict_table_t* table = nullptr;
if (page_rec_is_user_rec(rec)) { if (page_rec_is_user_rec(rec)) {
/*---------------------------------------------------*/ /*---------------------------------------------------*/
@@ -2727,17 +2603,15 @@ check_rec:
/* 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, field = rec_get_nth_field_old(rec,
DICT_FLD__SYS_TABLE_IDS__NAME, &len); DICT_FLD__SYS_TABLE_IDS__NAME, &len);
/* Load the table definition to memory */ table = dict_sys.load_table(
char* table_name = mem_heap_strdupl( {reinterpret_cast<const char*>(field),
heap, (char*) field, len); len}, ignore_err);
table = dict_load_table(table_name, ignore_err);
} }
} }
} }
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
mtr_commit(&mtr); mtr.commit();
mem_heap_free(heap);
return(table); return(table);
} }
@@ -2778,8 +2652,6 @@ dict_load_foreign_cols(
/*===================*/ /*===================*/
dict_foreign_t* foreign)/*!< in/out: foreign constraint object */ dict_foreign_t* foreign)/*!< in/out: foreign constraint object */
{ {
dict_table_t* sys_foreign_cols;
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;
@@ -2804,10 +2676,8 @@ dict_load_foreign_cols(
mtr_start(&mtr); mtr_start(&mtr);
sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS"); dict_index_t* sys_index = dict_sys.sys_foreign_cols->indexes.start;
ut_ad(!dict_sys.sys_foreign_cols->not_redundant());
sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes);
ut_ad(!dict_table_is_comp(sys_foreign_cols));
tuple = dtuple_create(foreign->heap, 1); tuple = dtuple_create(foreign->heap, 1);
dfield = dtuple_get_nth_field(tuple, 0); dfield = dtuple_get_nth_field(tuple, 0);
@@ -2918,9 +2788,7 @@ dict_load_foreign(
stack. */ stack. */
{ {
dict_foreign_t* foreign; dict_foreign_t* foreign;
dict_table_t* sys_foreign;
btr_pcur_t pcur; btr_pcur_t pcur;
dict_index_t* sys_index;
dtuple_t* tuple; dtuple_t* tuple;
mem_heap_t* heap2; mem_heap_t* heap2;
dfield_t* dfield; dfield_t* dfield;
@@ -2944,10 +2812,8 @@ dict_load_foreign(
mtr_start(&mtr); mtr_start(&mtr);
sys_foreign = dict_table_get_low("SYS_FOREIGN"); dict_index_t* sys_index = dict_sys.sys_foreign->indexes.start;
ut_ad(!dict_sys.sys_foreign->not_redundant());
sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes);
ut_ad(!dict_table_is_comp(sys_foreign));
tuple = dtuple_create(heap2, 1); tuple = dtuple_create(heap2, 1);
dfield = dtuple_get_nth_field(tuple, 0); dfield = dtuple_get_nth_field(tuple, 0);
@@ -2965,7 +2831,7 @@ dict_load_foreign(
ib::error() << "Cannot load foreign constraint " << id ib::error() << "Cannot load foreign constraint " << id
<< ": could not find the relevant record in " << ": could not find the relevant record in "
<< "SYS_FOREIGN"; "SYS_FOREIGN";
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
mtr_commit(&mtr); mtr_commit(&mtr);
@@ -3033,10 +2899,12 @@ dict_load_foreign(
dict_load_foreign_cols(foreign); dict_load_foreign_cols(foreign);
ref_table = dict_table_check_if_in_cache_low( ref_table = dict_sys.find_table(
foreign->referenced_table_name_lookup); {foreign->referenced_table_name_lookup,
for_table = dict_table_check_if_in_cache_low( strlen(foreign->referenced_table_name_lookup)});
foreign->foreign_table_name_lookup); for_table = dict_sys.find_table(
{foreign->foreign_table_name_lookup,
strlen(foreign->foreign_table_name_lookup)});
if (!for_table) { if (!for_table) {
/* To avoid recursively loading the tables related through /* To avoid recursively loading the tables related through
@@ -3101,8 +2969,6 @@ dict_load_foreigns(
btr_pcur_t pcur; btr_pcur_t pcur;
dtuple_t* tuple; dtuple_t* tuple;
dfield_t* dfield; dfield_t* dfield;
dict_index_t* sec_index;
dict_table_t* sys_foreign;
const rec_t* rec; const rec_t* rec;
const byte* field; const byte* field;
ulint len; ulint len;
@@ -3113,24 +2979,21 @@ dict_load_foreigns(
dict_sys.assert_locked(); dict_sys.assert_locked();
sys_foreign = dict_table_get_low("SYS_FOREIGN"); if (!dict_sys.sys_foreign || !dict_sys.sys_foreign_cols) {
if (ignore_err & DICT_ERR_IGNORE_FK_NOKEY) {
if (sys_foreign == NULL) { DBUG_RETURN(DB_SUCCESS);
/* No foreign keys defined yet in this database */ }
sql_print_information("InnoDB: No foreign key system tables"
ib::info() << "No foreign key system tables in the database"; " in the database");
DBUG_RETURN(DB_ERROR); DBUG_RETURN(DB_ERROR);
} }
ut_ad(!dict_table_is_comp(sys_foreign)); ut_ad(!dict_sys.sys_foreign->not_redundant());
mtr_start(&mtr); mtr_start(&mtr);
/* Get the secondary index based on FOR_NAME from table dict_index_t *sec_index = dict_table_get_next_index(
SYS_FOREIGN */ dict_table_get_first_index(dict_sys.sys_foreign));
ut_ad(!strcmp(sec_index->fields[0].name, "FOR_NAME"));
sec_index = dict_table_get_next_index(
dict_table_get_first_index(sys_foreign));
ut_ad(!dict_index_is_clust(sec_index));
start_load: start_load:
tuple = dtuple_create_from_mem(tuple_buf, sizeof(tuple_buf), 1, 0); tuple = dtuple_create_from_mem(tuple_buf, sizeof(tuple_buf), 1, 0);

View File

@@ -123,85 +123,73 @@ bool dict_col_t::same_encoding(uint16_t a, uint16_t b)
return false; return false;
} }
/** Create a table memory object. /** Create metadata.
@param name table name @param name table name
@param space tablespace @param space tablespace
@param n_cols total number of columns (both virtual and non-virtual) @param n_cols total number of columns (both virtual and non-virtual)
@param n_v_cols number of virtual columns @param n_v_cols number of virtual columns
@param flags table flags @param flags table flags
@param flags2 table flags2 @param flags2 table flags2
@return own: table object */ @return newly allocated table object */
dict_table_t *dict_mem_table_create(const char *name, fil_space_t *space, dict_table_t *dict_table_t::create(const span<const char> &name,
ulint n_cols, ulint n_v_cols, ulint flags, fil_space_t *space,
ulint flags2) ulint n_cols, ulint n_v_cols, ulint flags,
ulint flags2)
{ {
dict_table_t* table; ut_ad(!space || space->purpose == FIL_TYPE_TABLESPACE ||
mem_heap_t* heap; space->purpose == FIL_TYPE_TEMPORARY ||
space->purpose == FIL_TYPE_IMPORT);
ut_a(dict_tf2_is_valid(flags, flags2));
ut_a(!(flags2 & DICT_TF2_UNUSED_BIT_MASK));
ut_ad(name); mem_heap_t *heap= mem_heap_create(DICT_HEAP_SIZE);
ut_ad(!space
|| space->purpose == FIL_TYPE_TABLESPACE
|| space->purpose == FIL_TYPE_TEMPORARY
|| space->purpose == FIL_TYPE_IMPORT);
ut_a(dict_tf2_is_valid(flags, flags2));
ut_a(!(flags2 & DICT_TF2_UNUSED_BIT_MASK));
heap = mem_heap_create(DICT_HEAP_SIZE); dict_table_t *table= static_cast<dict_table_t*>
(mem_heap_zalloc(heap, sizeof(*table)));
table = static_cast<dict_table_t*>( lock_table_lock_list_init(&table->locks);
mem_heap_zalloc(heap, sizeof(*table))); UT_LIST_INIT(table->indexes, &dict_index_t::indexes);
lock_table_lock_list_init(&table->locks);
UT_LIST_INIT(table->indexes, &dict_index_t::indexes);
#ifdef BTR_CUR_HASH_ADAPT #ifdef BTR_CUR_HASH_ADAPT
UT_LIST_INIT(table->freed_indexes, &dict_index_t::indexes); UT_LIST_INIT(table->freed_indexes, &dict_index_t::indexes);
#endif /* BTR_CUR_HASH_ADAPT */ #endif /* BTR_CUR_HASH_ADAPT */
table->heap= heap;
table->heap = heap; ut_d(table->magic_n= DICT_TABLE_MAGIC_N);
ut_d(table->magic_n = DICT_TABLE_MAGIC_N); table->flags= static_cast<unsigned>(flags) & ((1U << DICT_TF_BITS) - 1);
table->flags2= static_cast<unsigned>(flags2) & ((1U << DICT_TF2_BITS) - 1);
table->name.m_name= mem_strdupl(name.data(), name.size());
table->is_system_db= dict_mem_table_is_system(table->name.m_name);
table->space= space;
table->space_id= space ? space->id : ULINT_UNDEFINED;
table->n_t_cols= static_cast<unsigned>(n_cols + DATA_N_SYS_COLS) &
dict_index_t::MAX_N_FIELDS;
table->n_v_cols= static_cast<unsigned>(n_v_cols) &
dict_index_t::MAX_N_FIELDS;
table->n_cols= static_cast<unsigned>(table->n_t_cols - table->n_v_cols) &
dict_index_t::MAX_N_FIELDS;
table->cols= static_cast<dict_col_t*>
(mem_heap_alloc(heap, table->n_cols * sizeof *table->cols));
table->v_cols= static_cast<dict_v_col_t*>
(mem_heap_alloc(heap, n_v_cols * sizeof *table->v_cols));
for (ulint i = n_v_cols; i--; )
new (&table->v_cols[i]) dict_v_col_t();
table->autoinc_lock= static_cast<ib_lock_t*>
(mem_heap_alloc(heap, sizeof *table->autoinc_lock));
/* If the table has an FTS index or we are in the process
of building one, create the table->fts */
if (dict_table_has_fts_index(table) ||
DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID |
DICT_TF2_FTS_ADD_DOC_ID))
{
table->fts= fts_create(table);
table->fts->cache= fts_cache_create(table);
}
table->flags = static_cast<unsigned>(flags) new (&table->foreign_set) dict_foreign_set();
& ((1U << DICT_TF_BITS) - 1); new (&table->referenced_set) dict_foreign_set();
table->flags2 = static_cast<unsigned>(flags2)
& ((1U << DICT_TF2_BITS) - 1);
table->name.m_name = mem_strdup(name);
table->is_system_db = dict_mem_table_is_system(table->name.m_name);
table->space = space;
table->space_id = space ? space->id : ULINT_UNDEFINED;
table->n_t_cols = static_cast<unsigned>(n_cols + DATA_N_SYS_COLS)
& dict_index_t::MAX_N_FIELDS;
table->n_v_cols = static_cast<unsigned>(n_v_cols)
& dict_index_t::MAX_N_FIELDS;
table->n_cols = static_cast<unsigned>(
table->n_t_cols - table->n_v_cols)
& dict_index_t::MAX_N_FIELDS;
table->cols = static_cast<dict_col_t*>( return table;
mem_heap_alloc(heap, table->n_cols * sizeof(dict_col_t)));
table->v_cols = static_cast<dict_v_col_t*>(
mem_heap_alloc(heap, n_v_cols * sizeof(*table->v_cols)));
for (ulint i = n_v_cols; i--; ) {
new (&table->v_cols[i]) dict_v_col_t();
}
table->autoinc_lock = static_cast<ib_lock_t*>(
mem_heap_alloc(heap, sizeof *table->autoinc_lock));
/* If the table has an FTS index or we are in the process
of building one, create the table->fts */
if (dict_table_has_fts_index(table)
|| DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
|| DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) {
table->fts = fts_create(table);
table->fts->cache = fts_cache_create(table);
}
new(&table->foreign_set) dict_foreign_set();
new(&table->referenced_set) dict_foreign_set();
return(table);
} }
/****************************************************************//** /****************************************************************//**

View File

@@ -25,7 +25,6 @@ Created Jan 06, 2010 Vasil Dimov
*******************************************************/ *******************************************************/
#include "dict0stats.h" #include "dict0stats.h"
#include "dict0priv.h"
#include "ut0ut.h" #include "ut0ut.h"
#include "ut0rnd.h" #include "ut0rnd.h"
#include "dyn0buf.h" #include "dyn0buf.h"
@@ -143,6 +142,20 @@ typedef ut_allocator<std::pair<const char* const, dict_index_t*> >
typedef std::map<const char*, dict_index_t*, ut_strcmp_functor, typedef std::map<const char*, dict_index_t*, ut_strcmp_functor,
index_map_t_allocator> index_map_t; index_map_t_allocator> index_map_t;
inline bool dict_table_t::is_stats_table() const
{
return !strcmp(name.m_name, TABLE_STATS_NAME) ||
!strcmp(name.m_name, INDEX_STATS_NAME);
}
bool trx_t::has_stats_table_lock() const
{
for (const lock_t *l : lock.table_locks)
if (l && l->un_member.tab_lock.table->is_stats_table())
return true;
return false;
}
/*********************************************************************//** /*********************************************************************//**
Checks whether an index should be ignored in stats manipulations: Checks whether an index should be ignored in stats manipulations:
* stats fetch * stats fetch
@@ -179,7 +192,7 @@ struct dict_col_meta_t
struct dict_table_schema_t struct dict_table_schema_t
{ {
/** table name */ /** table name */
const char *table_name; span<const char> table_name;
/** table name in SQL */ /** table name in SQL */
const char *table_name_sql; const char *table_name_sql;
/** number of columns */ /** number of columns */
@@ -190,7 +203,7 @@ struct dict_table_schema_t
static const dict_table_schema_t table_stats_schema = static const dict_table_schema_t table_stats_schema =
{ {
TABLE_STATS_NAME, TABLE_STATS_NAME_PRINT, 6, {C_STRING_WITH_LEN(TABLE_STATS_NAME)}, TABLE_STATS_NAME_PRINT, 6,
{ {
{"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192}, {"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
{"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597}, {"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597},
@@ -203,7 +216,7 @@ static const dict_table_schema_t table_stats_schema =
static const dict_table_schema_t index_stats_schema = static const dict_table_schema_t index_stats_schema =
{ {
INDEX_STATS_NAME, INDEX_STATS_NAME_PRINT, 8, {C_STRING_WITH_LEN(INDEX_STATS_NAME)}, INDEX_STATS_NAME_PRINT, 8,
{ {
{"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192}, {"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
{"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597}, {"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597},
@@ -327,7 +340,7 @@ dict_table_schema_check(
returned */ returned */
size_t errstr_sz) /*!< in: errstr size */ size_t errstr_sz) /*!< in: errstr size */
{ {
const dict_table_t* table = dict_table_get_low(req_schema->table_name); const dict_table_t* table= dict_sys.load_table(req_schema->table_name);
if (!table) { if (!table) {
if (req_schema == &table_stats_schema) { if (req_schema == &table_stats_schema) {

View File

@@ -47,6 +47,7 @@ Created 10/25/1995 Heikki Tuuri
#include "buf0lru.h" #include "buf0lru.h"
#include "ibuf0ibuf.h" #include "ibuf0ibuf.h"
#include "buf0flu.h" #include "buf0flu.h"
#include "log.h"
#ifdef UNIV_LINUX #ifdef UNIV_LINUX
# include <sys/types.h> # include <sys/types.h>
# include <sys/sysmacros.h> # include <sys/sysmacros.h>
@@ -2195,7 +2196,7 @@ statement to update the dictionary tables if they are incorrect.
@param[in] purpose FIL_TYPE_TABLESPACE or FIL_TYPE_TEMPORARY @param[in] purpose FIL_TYPE_TABLESPACE or FIL_TYPE_TEMPORARY
@param[in] id tablespace ID @param[in] id tablespace ID
@param[in] flags expected FSP_SPACE_FLAGS @param[in] flags expected FSP_SPACE_FLAGS
@param[in] space_name tablespace name of the datafile @param[in] name table name
If file-per-table, it is the table name in the databasename/tablename format If file-per-table, it is the table name in the databasename/tablename format
@param[in] path_in expected filepath, usually read from dictionary @param[in] path_in expected filepath, usually read from dictionary
@param[out] err DB_SUCCESS or error code @param[out] err DB_SUCCESS or error code
@@ -2207,37 +2208,40 @@ fil_ibd_open(
fil_type_t purpose, fil_type_t purpose,
ulint id, ulint id,
ulint flags, ulint flags,
const table_name_t tablename, fil_space_t::name_type name,
const char* path_in, const char* path_in,
dberr_t* err) dberr_t* err)
{ {
mysql_mutex_lock(&fil_system.mutex); mysql_mutex_lock(&fil_system.mutex);
if (fil_space_t* space = fil_space_get_by_id(id)) { fil_space_t* space = fil_space_get_by_id(id);
mysql_mutex_unlock(&fil_system.mutex); mysql_mutex_unlock(&fil_system.mutex);
if (space) {
if (space && validate && !srv_read_only_mode) { if (validate && !srv_read_only_mode) {
fsp_flags_try_adjust(space, fsp_flags_try_adjust(space,
flags & ~FSP_FLAGS_MEM_MASK); flags & ~FSP_FLAGS_MEM_MASK);
} }
return space; return space;
} }
mysql_mutex_unlock(&fil_system.mutex);
dberr_t local_err = DB_SUCCESS;
/* Table flags can be ULINT_UNDEFINED if
dict_tf_to_fsp_flags_failure is set. */
if (flags == ULINT_UNDEFINED) {
corrupted:
local_err = DB_CORRUPTION;
func_exit:
if (err) *err = local_err;
return space;
}
ut_ad(fil_space_t::is_valid_flags(flags & ~FSP_FLAGS_MEM_MASK, id));
Datafile df_default; /* default location */ Datafile df_default; /* default location */
RemoteDatafile df_remote; /* remote location */ RemoteDatafile df_remote; /* remote location */
ulint tablespaces_found = 0; ulint tablespaces_found = 0;
ulint valid_tablespaces_found = 0; ulint valid_tablespaces_found = 0;
/* Table flags can be ULINT_UNDEFINED if
dict_tf_to_fsp_flags_failure is set. */
if (flags == ULINT_UNDEFINED) {
corrupted:
if (err) *err = DB_CORRUPTION;
return NULL;
}
ut_ad(fil_space_t::is_valid_flags(flags & ~FSP_FLAGS_MEM_MASK, id));
df_default.init(flags); df_default.init(flags);
df_remote.init(flags); df_remote.init(flags);
@@ -2245,12 +2249,11 @@ corrupted:
while avoiding unecessary effort. */ while avoiding unecessary effort. */
/* We will always look for an ibd in the default location. */ /* We will always look for an ibd in the default location. */
df_default.make_filepath(nullptr, {tablename.m_name, df_default.make_filepath(nullptr, name, IBD);
strlen(tablename.m_name)}, IBD);
/* Look for a filepath embedded in an ISL where the default file /* Look for a filepath embedded in an ISL where the default file
would be. */ would be. */
if (df_remote.open_link_file(tablename)) { if (df_remote.open_link_file(name)) {
validate = true; validate = true;
if (df_remote.open_read_only(true) == DB_SUCCESS) { if (df_remote.open_read_only(true) == DB_SUCCESS) {
ut_ad(df_remote.is_open()); ut_ad(df_remote.is_open());
@@ -2314,8 +2317,10 @@ corrupted:
First, bail out if no tablespace files were found. */ First, bail out if no tablespace files were found. */
if (valid_tablespaces_found == 0) { if (valid_tablespaces_found == 0) {
os_file_get_last_error(true); os_file_get_last_error(true);
ib::error() << "Could not find a valid tablespace file for `" sql_print_error("InnoDB: Could not find a valid tablespace"
<< tablename << "`. " << TROUBLESHOOT_DATADICT_MSG; " file for %.*s. %s",
static_cast<int>(name.size()), name.data(),
TROUBLESHOOT_DATADICT_MSG);
goto corrupted; goto corrupted;
} }
if (!validate) { if (!validate) {
@@ -2324,22 +2329,19 @@ corrupted:
/* Do not open any tablespaces if more than one tablespace with /* Do not open any tablespaces if more than one tablespace with
the correct space ID and flags were found. */ the correct space ID and flags were found. */
if (tablespaces_found > 1) { if (df_default.is_open() && df_remote.is_open()) {
ib::error() << "A tablespace for `" << tablename ib::error()
<< "` has been found in multiple places;"; << "A tablespace has been found in multiple places: "
<< df_default.filepath()
if (df_default.is_open()) { << "(Space ID=" << df_default.space_id()
ib::error() << "Default location: " << ", Flags=" << df_default.flags()
<< df_default.filepath() << ") and "
<< ", Space ID=" << df_default.space_id() << df_remote.filepath()
<< ", Flags=" << df_default.flags(); << "(Space ID=" << df_remote.space_id()
} << ", Flags=" << df_remote.flags()
if (df_remote.is_open()) { << (valid_tablespaces_found > 1 || srv_force_recovery
ib::error() << "Remote location: " ? "); will not open"
<< df_remote.filepath() : ")");
<< ", Space ID=" << df_remote.space_id()
<< ", Flags=" << df_remote.flags();
}
/* Force-recovery will allow some tablespaces to be /* Force-recovery will allow some tablespaces to be
skipped by REDO if there was more than one file found. skipped by REDO if there was more than one file found.
@@ -2349,9 +2351,6 @@ corrupted:
recovery and there is only one good tablespace, ignore recovery and there is only one good tablespace, ignore
any bad tablespaces. */ any bad tablespaces. */
if (valid_tablespaces_found > 1 || srv_force_recovery > 0) { if (valid_tablespaces_found > 1 || srv_force_recovery > 0) {
ib::error() << "Will not open tablespace `"
<< tablename << "`";
/* If the file is not open it cannot be valid. */ /* If the file is not open it cannot be valid. */
ut_ad(df_default.is_open() || !df_default.is_valid()); ut_ad(df_default.is_open() || !df_default.is_valid());
ut_ad(df_remote.is_open() || !df_remote.is_valid()); ut_ad(df_remote.is_open() || !df_remote.is_valid());
@@ -2363,8 +2362,8 @@ corrupted:
goto corrupted; goto corrupted;
} }
error: error:
if (err) *err = DB_ERROR; local_err = DB_ERROR;
return NULL; goto func_exit;
} }
/* There is only one valid tablespace found and we did /* There is only one valid tablespace found and we did
@@ -2395,8 +2394,7 @@ skip_validate:
first_page) first_page)
: NULL; : NULL;
fil_space_t* space = fil_space_t::create( space = fil_space_t::create(id, flags, purpose, crypt_data);
id, flags, purpose, crypt_data);
if (!space) { if (!space) {
goto error; goto error;
} }
@@ -2420,8 +2418,7 @@ skip_validate:
} }
} }
if (err) *err = DB_SUCCESS; goto func_exit;
return space;
} }
/** Discover the correct IBD file to open given a remote or missing /** Discover the correct IBD file to open given a remote or missing
@@ -2485,14 +2482,11 @@ fil_ibd_discover(
case SRV_OPERATION_RESTORE: case SRV_OPERATION_RESTORE:
break; break;
case SRV_OPERATION_NORMAL: case SRV_OPERATION_NORMAL:
char* name = const_cast<char*>(db); size_t len= strlen(db);
size_t len= strlen(name); if (len <= 4 || strcmp(db + len - 4, dot_ext[IBD])) {
if (len <= 4 || strcmp(name + len - 4, dot_ext[IBD])) {
break; break;
} }
name[len - 4] = '\0'; df_rem_per.open_link_file({db, len - 4});
df_rem_per.open_link_file(table_name_t{name});
name[len - 4] = *dot_ext[IBD];
if (!df_rem_per.filepath()) { if (!df_rem_per.filepath()) {
break; break;

View File

@@ -837,7 +837,7 @@ open that file, and read the contents into m_filepath.
@param name table name @param name table name
@return filepath() @return filepath()
@retval nullptr if the .isl file does not exist or cannot be read */ @retval nullptr if the .isl file does not exist or cannot be read */
const char *RemoteDatafile::open_link_file(const table_name_t &name) const char *RemoteDatafile::open_link_file(const fil_space_t::name_type name)
{ {
if (!m_link_filepath) if (!m_link_filepath)
m_link_filepath= fil_make_filepath(nullptr, name, ISL, false); m_link_filepath= fil_make_filepath(nullptr, name, ISL, false);

View File

@@ -34,7 +34,6 @@ Full Text Search interface
#include "fts0types.ic" #include "fts0types.ic"
#include "fts0vlc.ic" #include "fts0vlc.ic"
#include "fts0plugin.h" #include "fts0plugin.h"
#include "dict0priv.h"
#include "dict0stats.h" #include "dict0stats.h"
#include "btr0pcur.h" #include "btr0pcur.h"
@@ -1675,8 +1674,9 @@ fts_create_in_mem_aux_table(
const dict_table_t* table, const dict_table_t* table,
ulint n_cols) ulint n_cols)
{ {
dict_table_t* new_table = dict_mem_table_create( dict_table_t* new_table = dict_table_t::create(
aux_table_name, NULL, n_cols, 0, table->flags, {aux_table_name,strlen(aux_table_name)},
nullptr, n_cols, 0, table->flags,
table->space_id == TRX_SYS_SPACE table->space_id == TRX_SYS_SPACE
? 0 : table->space_id == SRV_TMP_SPACE_ID ? 0 : table->space_id == SRV_TMP_SPACE_ID
? DICT_TF2_TEMPORARY : DICT_TF2_USE_FILE_PER_TABLE); ? DICT_TF2_TEMPORARY : DICT_TF2_USE_FILE_PER_TABLE);
@@ -5645,7 +5645,8 @@ fts_valid_stopword_table(
return(NULL); return(NULL);
} }
table = dict_table_get_low(stopword_table_name); table = dict_sys.load_table(
{stopword_table_name, strlen(stopword_table_name)});
if (!table) { if (!table) {
ib::error() << "User stopword table " << stopword_table_name ib::error() << "User stopword table " << stopword_table_name

View File

@@ -2554,7 +2554,7 @@ void fts_optimize_add_table(dict_table_t* table)
} }
/* Make sure table with FTS index cannot be evicted */ /* Make sure table with FTS index cannot be evicted */
dict_table_prevent_eviction(table); dict_sys.prevent_eviction(table);
msg = fts_optimize_create_msg(FTS_MSG_ADD_TABLE, table); msg = fts_optimize_create_msg(FTS_MSG_ADD_TABLE, table);

View File

@@ -80,7 +80,6 @@ this program; if not, write to the Free Software Foundation, Inc.,
#include "btr0defragment.h" #include "btr0defragment.h"
#include "dict0crea.h" #include "dict0crea.h"
#include "dict0dict.h" #include "dict0dict.h"
#include "dict0priv.h"
#include "dict0stats.h" #include "dict0stats.h"
#include "dict0stats_bg.h" #include "dict0stats_bg.h"
#include "fil0fil.h" #include "fil0fil.h"
@@ -148,7 +147,6 @@ void close_thread_tables(THD* thd);
#include <sstream> #include <sstream>
#ifdef WITH_WSREP #ifdef WITH_WSREP
#include "dict0priv.h"
#include <mysql/service_md5.h> #include <mysql/service_md5.h>
#include "wsrep_sst.h" #include "wsrep_sst.h"
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
@@ -1277,7 +1275,7 @@ static ibool innodb_drop_database_ignore_fk(void*,void*) { return false; }
struct innodb_drop_database_fk_report struct innodb_drop_database_fk_report
{ {
/** database name, with trailing '/' */ /** database name, with trailing '/' */
const st_::span<char> name; const span<const char> name;
/** whether errors were found */ /** whether errors were found */
bool violated; bool violated;
}; };
@@ -9798,8 +9796,11 @@ wsrep_append_foreign_key(
if (referenced) { if (referenced) {
foreign->referenced_table = foreign->referenced_table =
dict_table_get_low( dict_sys.load_table(
foreign->referenced_table_name_lookup); {foreign->referenced_table_name_lookup,
strlen(foreign->
referenced_table_name_lookup)
});
if (foreign->referenced_table) { if (foreign->referenced_table) {
foreign->referenced_index = foreign->referenced_index =
dict_foreign_find_index( dict_foreign_find_index(
@@ -9811,8 +9812,10 @@ wsrep_append_foreign_key(
} }
} else { } else {
foreign->foreign_table = foreign->foreign_table =
dict_table_get_low( dict_sys.load_table(
foreign->foreign_table_name_lookup); {foreign->foreign_table_name_lookup,
strlen(foreign->
foreign_table_name_lookup)});
if (foreign->foreign_table) { if (foreign->foreign_table) {
foreign->foreign_index = foreign->foreign_index =
@@ -10478,8 +10481,8 @@ create_table_info_t::create_table_def()
const ulint actual_n_cols = n_cols const ulint actual_n_cols = n_cols
+ (m_flags2 & DICT_TF2_FTS && !has_doc_id_col); + (m_flags2 & DICT_TF2_FTS && !has_doc_id_col);
table = dict_mem_table_create(m_table_name, NULL, table = dict_table_t::create({m_table_name,table_name_len}, nullptr,
actual_n_cols, num_v, m_flags, m_flags2); actual_n_cols, num_v, m_flags, m_flags2);
/* Set the hidden doc_id column. */ /* Set the hidden doc_id column. */
if (m_flags2 & DICT_TF2_FTS) { if (m_flags2 & DICT_TF2_FTS) {
@@ -10696,7 +10699,7 @@ err_col:
"temporary table creation."); "temporary table creation.");
} }
table->id = dict_sys.get_temporary_table_id(); table->id = dict_sys.acquire_temporary_table_id();
ut_ad(dict_tf_get_rec_format(table->flags) ut_ad(dict_tf_get_rec_format(table->flags)
!= REC_FORMAT_COMPRESSED); != REC_FORMAT_COMPRESSED);
table->space_id = SRV_TMP_SPACE_ID; table->space_id = SRV_TMP_SPACE_ID;
@@ -12140,7 +12143,7 @@ create_table_info_t::create_foreign_keys()
ut_ad(alter_info); ut_ad(alter_info);
List_iterator_fast<Key> key_it(alter_info->key_list); List_iterator_fast<Key> key_it(alter_info->key_list);
dict_table_t* table = dict_table_get_low(name); dict_table_t* table = dict_sys.find_table({name,strlen(name)});
if (!table) { if (!table) {
ib_foreign_warn(m_trx, DB_CANNOT_ADD_CONSTRAINT, create_name, ib_foreign_warn(m_trx, DB_CANNOT_ADD_CONSTRAINT, create_name,
"%s table %s foreign key constraint" "%s table %s foreign key constraint"
@@ -12630,13 +12633,12 @@ int create_table_info_t::create_table(bool create_fk)
if (err == DB_SUCCESS) { if (err == DB_SUCCESS) {
/* Check that also referencing constraints are ok */ /* Check that also referencing constraints are ok */
dict_names_t fk_tables; dict_names_t fk_tables;
err = dict_load_foreigns(m_table_name, NULL, err = dict_load_foreigns(m_table_name, NULL, false, true,
false, true, DICT_ERR_IGNORE_NONE, fk_tables);
DICT_ERR_IGNORE_NONE,
fk_tables);
while (err == DB_SUCCESS && !fk_tables.empty()) { while (err == DB_SUCCESS && !fk_tables.empty()) {
dict_load_table(fk_tables.front(), dict_sys.load_table(
DICT_ERR_IGNORE_NONE); {fk_tables.front(), strlen(fk_tables.front())},
DICT_ERR_IGNORE_NONE);
fk_tables.pop_front(); fk_tables.pop_front();
} }
} }

View File

@@ -35,7 +35,7 @@ Smart ALTER TABLE
#include "btr0sea.h" #include "btr0sea.h"
#include "dict0crea.h" #include "dict0crea.h"
#include "dict0dict.h" #include "dict0dict.h"
#include "dict0priv.h" #include "dict0load.h"
#include "dict0stats.h" #include "dict0stats.h"
#include "dict0stats_bg.h" #include "dict0stats_bg.h"
#include "log0log.h" #include "log0log.h"
@@ -56,11 +56,9 @@ Smart ALTER TABLE
#include "row0sel.h" #include "row0sel.h"
#include "ha_innodb.h" #include "ha_innodb.h"
#include "ut0stage.h" #include "ut0stage.h"
#include "span.h"
#include <thread> #include <thread>
#include <sstream> #include <sstream>
using st_::span;
/** File format constraint for ALTER TABLE */ /** File format constraint for ALTER TABLE */
extern ulong innodb_instant_alter_column_allowed; extern ulong innodb_instant_alter_column_allowed;
@@ -2054,6 +2052,12 @@ ha_innobase::check_if_supported_inplace_alter(
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
} }
if (!dict_sys.sys_tables_exist()) {
ha_alter_info->unsupported_reason
= "missing InnoDB system tables";
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
}
/* Only support online add foreign key constraint when /* Only support online add foreign key constraint when
check_foreigns is turned off */ check_foreigns is turned off */
if ((ha_alter_info->handler_flags & ALTER_ADD_FOREIGN_KEY) if ((ha_alter_info->handler_flags & ALTER_ADD_FOREIGN_KEY)
@@ -6397,9 +6401,9 @@ new_clustered_failed:
DBUG_ASSERT(!add_fts_doc_id_idx || (flags2 & DICT_TF2_FTS)); DBUG_ASSERT(!add_fts_doc_id_idx || (flags2 & DICT_TF2_FTS));
ctx->new_table = dict_mem_table_create( ctx->new_table = dict_table_t::create(
new_table_name, NULL, n_cols + n_v_cols, n_v_cols, {new_table_name, tablen + partlen}, nullptr,
flags, flags2); n_cols + n_v_cols, n_v_cols, flags, flags2);
/* The rebuilt indexed_table will use the renamed /* The rebuilt indexed_table will use the renamed
column names. */ column names. */
@@ -6796,7 +6800,9 @@ wrong_column_name:
} }
} }
if (dict_table_get_low(ctx->new_table->name.m_name)) { if (dict_sys.find_table(
{ctx->new_table->name.m_name,
strlen(ctx->new_table->name.m_name)})) {
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), my_error(ER_TABLE_EXISTS_ERROR, MYF(0),
ctx->new_table->name.m_name); ctx->new_table->name.m_name);
goto new_clustered_failed; goto new_clustered_failed;
@@ -9731,17 +9737,14 @@ innobase_update_foreign_cache(
/* For complete loading of foreign keys, all associated tables must /* For complete loading of foreign keys, all associated tables must
also be loaded. */ also be loaded. */
while (err == DB_SUCCESS && !fk_tables.empty()) { while (err == DB_SUCCESS && !fk_tables.empty()) {
dict_table_t* table = dict_load_table( const char *f = fk_tables.front();
fk_tables.front(), DICT_ERR_IGNORE_NONE); if (!dict_sys.load_table({f, strlen(f)})) {
if (table == NULL) {
err = DB_TABLE_NOT_FOUND; err = DB_TABLE_NOT_FOUND;
ib::error() ib::error()
<< "Failed to load table '" << "Failed to load table "
<< table_name_t(const_cast<char*> << table_name_t(const_cast<char*>(f))
(fk_tables.front())) << " which has a foreign key constraint with"
<< "' which has a foreign key constraint with" << user_table->name;
<< " table '" << user_table->name << "'.";
break; break;
} }

View File

@@ -4820,6 +4820,41 @@ i_s_dict_fill_sys_tables(
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/** Convert one SYS_TABLES record to dict_table_t.
@param pcur persistent cursor position on SYS_TABLES record
@param rec record to read from (nullptr=use the dict_sys cache)
@param table the converted dict_table_t
@return error message
@retval nullptr on success */
static const char *i_s_sys_tables_rec(const btr_pcur_t &pcur, const rec_t *rec,
dict_table_t **table)
{
static_assert(DICT_FLD__SYS_TABLES__NAME == 0, "compatibility");
size_t len;
if (rec_get_1byte_offs_flag(pcur.old_rec))
{
len= rec_1_get_field_end_info(pcur.old_rec, 0);
if (len & REC_1BYTE_SQL_NULL_MASK)
return "corrupted SYS_TABLES.NAME";
}
else
{
len= rec_2_get_field_end_info(pcur.old_rec, 0);
static_assert(REC_2BYTE_EXTERN_MASK == 16384, "compatibility");
if (len >= REC_2BYTE_EXTERN_MASK)
return "corrupted SYS_TABLES.NAME";
}
const span<const char>name{reinterpret_cast<const char*>(pcur.old_rec), len};
if (rec)
return dict_load_table_low(name, rec, table);
*table= dict_sys.load_table(name);
return *table ? nullptr : "Table not found in cache";
}
/*******************************************************************//** /*******************************************************************//**
Function to go through each record in SYS_TABLES table, and fill the Function to go through each record in SYS_TABLES table, and fill the
information_schema.innodb_sys_tables table with related table information information_schema.innodb_sys_tables table with related table information
@@ -4833,8 +4868,6 @@ i_s_sys_tables_fill_table(
Item* ) /*!< in: condition (not used) */ Item* ) /*!< in: condition (not used) */
{ {
btr_pcur_t pcur; btr_pcur_t pcur;
const rec_t* rec;
mem_heap_t* heap;
mtr_t mtr; mtr_t mtr;
DBUG_ENTER("i_s_sys_tables_fill_table"); DBUG_ENTER("i_s_sys_tables_fill_table");
@@ -4845,21 +4878,23 @@ i_s_sys_tables_fill_table(
DBUG_RETURN(0); DBUG_RETURN(0);
} }
heap = mem_heap_create(1000);
dict_sys.mutex_lock(); dict_sys.mutex_lock();
mtr_start(&mtr); mtr_start(&mtr);
rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES); for (const rec_t *rec = dict_startscan_system(&pcur, &mtr,
dict_sys.sys_tables);
rec; rec = dict_getnext_system(&pcur, &mtr)) {
if (rec_get_deleted_flag(rec, 0)) {
continue;
}
while (rec) {
const char* err_msg; const char* err_msg;
dict_table_t* table_rec; dict_table_t* table_rec;
/* Create and populate a dict_table_t structure with /* Create and populate a dict_table_t structure with
information from SYS_TABLES row */ information from SYS_TABLES row */
err_msg = dict_process_sys_tables_rec_and_mtr_commit( err_msg = i_s_sys_tables_rec(pcur, rec, &table_rec);
heap, rec, &table_rec, false, &mtr); mtr.commit();
dict_sys.mutex_unlock(); dict_sys.mutex_unlock();
if (!err_msg) { if (!err_msg) {
@@ -4875,17 +4910,13 @@ i_s_sys_tables_fill_table(
dict_mem_table_free(table_rec); dict_mem_table_free(table_rec);
} }
mem_heap_empty(heap);
/* Get the next record */ /* Get the next record */
dict_sys.mutex_lock(); dict_sys.mutex_lock();
mtr_start(&mtr); mtr.start();
rec = dict_getnext_system(&pcur, &mtr);
} }
mtr_commit(&mtr); mtr.commit();
dict_sys.mutex_unlock(); dict_sys.mutex_unlock();
mem_heap_free(heap);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@@ -5078,7 +5109,6 @@ i_s_sys_tables_fill_table_stats(
{ {
btr_pcur_t pcur; btr_pcur_t pcur;
const rec_t* rec; const rec_t* rec;
mem_heap_t* heap;
mtr_t mtr; mtr_t mtr;
DBUG_ENTER("i_s_sys_tables_fill_table_stats"); DBUG_ENTER("i_s_sys_tables_fill_table_stats");
@@ -5089,30 +5119,24 @@ i_s_sys_tables_fill_table_stats(
DBUG_RETURN(0); DBUG_RETURN(0);
} }
heap = mem_heap_create(1000);
dict_sys.freeze(); dict_sys.freeze();
dict_sys.mutex_lock(); dict_sys.mutex_lock();
mtr_start(&mtr); mtr_start(&mtr);
rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES); rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_tables);
while (rec) { while (rec) {
const char* err_msg; const char* err_msg;
dict_table_t* table_rec; dict_table_t* table_rec;
mtr.commit();
/* Fetch the dict_table_t structure corresponding to /* Fetch the dict_table_t structure corresponding to
this SYS_TABLES record */ this SYS_TABLES record */
err_msg = dict_process_sys_tables_rec_and_mtr_commit( err_msg = i_s_sys_tables_rec(pcur, nullptr, &table_rec);
heap, rec, &table_rec, true, &mtr);
ulint ref_count = table_rec ? table_rec->get_ref_count() : 0; ulint ref_count = table_rec ? table_rec->get_ref_count() : 0;
dict_sys.mutex_unlock(); dict_sys.mutex_unlock();
DBUG_EXECUTE_IF("test_sys_tablestats", {
if (strcmp("test/t1", table_rec->name.m_name) == 0 ) {
DEBUG_SYNC_C("dict_table_not_protected");
}});
if (table_rec != NULL) { if (table_rec != NULL) {
ut_ad(err_msg == NULL); ut_ad(err_msg == NULL);
i_s_dict_fill_sys_tablestats(thd, table_rec, ref_count, i_s_dict_fill_sys_tablestats(thd, table_rec, ref_count,
@@ -5125,7 +5149,6 @@ i_s_sys_tables_fill_table_stats(
} }
dict_sys.unfreeze(); dict_sys.unfreeze();
mem_heap_empty(heap);
/* Get the next record */ /* Get the next record */
dict_sys.freeze(); dict_sys.freeze();
@@ -5138,7 +5161,6 @@ i_s_sys_tables_fill_table_stats(
mtr_commit(&mtr); mtr_commit(&mtr);
dict_sys.mutex_unlock(); dict_sys.mutex_unlock();
dict_sys.unfreeze(); dict_sys.unfreeze();
mem_heap_free(heap);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@@ -5335,7 +5357,7 @@ i_s_sys_indexes_fill_table(
mtr_start(&mtr); mtr_start(&mtr);
/* Start scan the SYS_INDEXES table */ /* Start scan the SYS_INDEXES table */
rec = dict_startscan_system(&pcur, &mtr, SYS_INDEXES); rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_indexes);
/* Process each record in the table */ /* Process each record in the table */
while (rec) { while (rec) {
@@ -5553,7 +5575,7 @@ i_s_sys_columns_fill_table(
dict_sys.mutex_lock(); dict_sys.mutex_lock();
mtr_start(&mtr); mtr_start(&mtr);
rec = dict_startscan_system(&pcur, &mtr, SYS_COLUMNS); rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_columns);
while (rec) { while (rec) {
const char* err_msg; const char* err_msg;
@@ -5739,14 +5761,14 @@ i_s_sys_virtual_fill_table(
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str); RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
/* deny access to user without PROCESS_ACL privilege */ /* deny access to user without PROCESS_ACL privilege */
if (check_global_access(thd, PROCESS_ACL)) { if (check_global_access(thd, PROCESS_ACL) || !dict_sys.sys_virtual) {
DBUG_RETURN(0); DBUG_RETURN(0);
} }
dict_sys.mutex_lock(); dict_sys.mutex_lock();
mtr_start(&mtr); mtr_start(&mtr);
rec = dict_startscan_system(&pcur, &mtr, SYS_VIRTUAL); rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_virtual);
while (rec) { while (rec) {
const char* err_msg; const char* err_msg;
@@ -5936,7 +5958,7 @@ i_s_sys_fields_fill_table(
the next index. This is used to calculate prefix length */ the next index. This is used to calculate prefix length */
last_id = 0; last_id = 0;
rec = dict_startscan_system(&pcur, &mtr, SYS_FIELDS); rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_fields);
while (rec) { while (rec) {
ulint pos; ulint pos;
@@ -6127,8 +6149,7 @@ i_s_sys_foreign_fill_table(
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str); RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
/* deny access to user without PROCESS_ACL privilege */ /* deny access to user without PROCESS_ACL privilege */
if (check_global_access(thd, PROCESS_ACL)) { if (check_global_access(thd, PROCESS_ACL) || !dict_sys.sys_foreign) {
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@@ -6136,7 +6157,7 @@ i_s_sys_foreign_fill_table(
dict_sys.mutex_lock(); dict_sys.mutex_lock();
mtr_start(&mtr); mtr_start(&mtr);
rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN); rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_foreign);
while (rec) { while (rec) {
const char* err_msg; const char* err_msg;
@@ -6320,7 +6341,8 @@ i_s_sys_foreign_cols_fill_table(
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str); RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str);
/* deny access to user without PROCESS_ACL privilege */ /* deny access to user without PROCESS_ACL privilege */
if (check_global_access(thd, PROCESS_ACL)) { if (check_global_access(thd, PROCESS_ACL)
|| !dict_sys.sys_foreign_cols) {
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@@ -6328,7 +6350,7 @@ i_s_sys_foreign_cols_fill_table(
dict_sys.mutex_lock(); dict_sys.mutex_lock();
mtr_start(&mtr); mtr_start(&mtr);
rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN_COLS); rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_foreign_cols);
while (rec) { while (rec) {
const char* err_msg; const char* err_msg;

View File

@@ -455,8 +455,9 @@ ibuf_init_at_db_start(void)
mtr.commit(); mtr.commit();
ibuf.index = dict_mem_index_create( ibuf.index = dict_mem_index_create(
dict_mem_table_create("innodb_change_buffer", dict_table_t::create(
fil_system.sys_space, 1, 0, 0, 0), {C_STRING_WITH_LEN("innodb_change_buffer")},
fil_system.sys_space, 1, 0, 0, 0),
"CLUST_IND", "CLUST_IND",
DICT_CLUSTERED | DICT_IBUF, 1); DICT_CLUSTERED | DICT_IBUF, 1);
ibuf.index->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID; ibuf.index->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID;
@@ -1266,8 +1267,9 @@ ibuf_dummy_index_create(
dict_table_t* table; dict_table_t* table;
dict_index_t* index; dict_index_t* index;
table = dict_mem_table_create("IBUF_DUMMY", NULL, n, 0, table = dict_table_t::create({C_STRING_WITH_LEN("IBUF_DUMMY")},
comp ? DICT_TF_COMPACT : 0, 0); nullptr, n, 0,
comp ? DICT_TF_COMPACT : 0, 0);
index = dict_mem_index_create(table, "IBUF_DUMMY", 0, n); index = dict_mem_index_create(table, "IBUF_DUMMY", 0, n);

View File

@@ -117,15 +117,6 @@ dict_create_index_tree_in_mem(
dict_index_t* index, /*!< in/out: index */ dict_index_t* index, /*!< in/out: index */
const trx_t* trx); /*!< in: InnoDB transaction handle */ const trx_t* trx); /*!< in: InnoDB transaction handle */
/****************************************************************//**
Creates the foreign key constraints system tables inside InnoDB
at server bootstrap or server start if they are not found or are
not of the right form.
@return DB_SUCCESS or error code */
dberr_t
dict_create_or_check_foreign_constraint_tables(void);
/*================================================*/
/********************************************************************//** /********************************************************************//**
Generate a foreign key constraint name when it was not named by the user. Generate a foreign key constraint name when it was not named by the user.
A generated constraint has a name of the format dbname/tablename_ibfk_NUMBER, A generated constraint has a name of the format dbname/tablename_ibfk_NUMBER,
@@ -171,13 +162,6 @@ dict_foreigns_has_s_base_col(
const dict_foreign_set& local_fk_set, const dict_foreign_set& local_fk_set,
const dict_table_t* table); const dict_table_t* table);
/** Creates the virtual column system tables inside InnoDB
at server bootstrap or server start if they are not found or are
not of the right form.
@return DB_SUCCESS or error code */
dberr_t
dict_create_or_check_sys_virtual();
/********************************************************************//** /********************************************************************//**
Add a foreign key definition to the data dictionary tables. Add a foreign key definition to the data dictionary tables.
@return error code or DB_SUCCESS */ @return error code or DB_SUCCESS */

View File

@@ -1373,23 +1373,48 @@ class dict_sys_t
FIXME: merge the mutex and the latch, once MDEV-23484 has been fixed */ FIXME: merge the mutex and the latch, once MDEV-23484 has been fixed */
mysql_mutex_t mutex; mysql_mutex_t mutex;
public: public:
hash_table_t table_hash; /*!< hash table of the tables, based /** Indexes of SYS_TABLE[] */
on name */ enum
/** hash table of persistent table IDs */ {
hash_table_t table_id_hash; SYS_TABLES= 0,
dict_table_t* sys_tables; /*!< SYS_TABLES table */ SYS_INDEXES,
dict_table_t* sys_columns; /*!< SYS_COLUMNS table */ SYS_COLUMNS,
dict_table_t* sys_indexes; /*!< SYS_INDEXES table */ SYS_FIELDS,
dict_table_t* sys_fields; /*!< SYS_FIELDS table */ SYS_FOREIGN,
dict_table_t* sys_virtual; /*!< SYS_VIRTUAL table */ SYS_FOREIGN_COLS,
SYS_VIRTUAL
};
/** System table names */
static const span<const char> SYS_TABLE[];
/*=============================*/ /** all tables (persistent and temporary), hashed by name */
UT_LIST_BASE_NODE_T(dict_table_t) hash_table_t table_hash;
table_LRU; /*!< List of tables that can be evicted /** hash table of persistent table IDs */
from the cache */ hash_table_t table_id_hash;
UT_LIST_BASE_NODE_T(dict_table_t)
table_non_LRU; /*!< List of tables that can't be /** the SYS_TABLES table */
evicted from the cache */ dict_table_t *sys_tables;
/** the SYS_COLUMNS table */
dict_table_t *sys_columns;
/** the SYS_INDEXES table */
dict_table_t *sys_indexes;
/** the SYS_FIELDS table */
dict_table_t *sys_fields;
/** the SYS_FOREIGN table */
dict_table_t *sys_foreign;
/** the SYS_FOREIGN_COLS table */
dict_table_t *sys_foreign_cols;
/** the SYS_VIRTUAL table */
dict_table_t *sys_virtual;
/** @return whether all non-hard-coded system tables exist */
bool sys_tables_exist() const
{ return UNIV_LIKELY(sys_foreign && sys_foreign_cols && sys_virtual); }
/** list of persistent tables that can be evicted */
UT_LIST_BASE_NODE_T(dict_table_t) table_LRU;
/** list of persistent tables that cannot be evicted */
UT_LIST_BASE_NODE_T(dict_table_t) table_non_LRU;
private: private:
bool m_initialised= false; bool m_initialised= false;
@@ -1418,46 +1443,47 @@ public:
row_id= ut_uint64_align_up(id, ROW_ID_WRITE_MARGIN) + ROW_ID_WRITE_MARGIN; row_id= ut_uint64_align_up(id, ROW_ID_WRITE_MARGIN) + ROW_ID_WRITE_MARGIN;
} }
/** @return a new temporary table ID */ /** @return a new temporary table ID */
table_id_t get_temporary_table_id() { table_id_t acquire_temporary_table_id()
return temp_table_id.fetch_add(1, std::memory_order_relaxed); {
} return temp_table_id.fetch_add(1, std::memory_order_relaxed);
}
/** Look up a temporary table. /** Look up a temporary table.
@param id temporary table ID @param id temporary table ID
@return temporary table @return temporary table
@retval NULL if the table does not exist @retval nullptr if the table does not exist
(should only happen during the rollback of CREATE...SELECT) */ (should only happen during the rollback of CREATE...SELECT) */
dict_table_t* get_temporary_table(table_id_t id) dict_table_t *acquire_temporary_table(table_id_t id)
{ {
mysql_mutex_assert_owner(&mutex); mysql_mutex_assert_owner(&mutex);
dict_table_t* table; dict_table_t *table;
ulint fold = ut_fold_ull(id); ulint fold = ut_fold_ull(id);
HASH_SEARCH(id_hash, &temp_id_hash, fold, dict_table_t*, table, HASH_SEARCH(id_hash, &temp_id_hash, fold, dict_table_t*, table,
ut_ad(table->cached), table->id == id); ut_ad(table->cached), table->id == id);
if (UNIV_LIKELY(table != NULL)) { if (UNIV_LIKELY(table != nullptr))
DBUG_ASSERT(table->is_temporary()); {
DBUG_ASSERT(table->id >= DICT_HDR_FIRST_ID); DBUG_ASSERT(table->is_temporary());
table->acquire(); DBUG_ASSERT(table->id >= DICT_HDR_FIRST_ID);
} table->acquire();
return table; }
} return table;
}
/** Look up a persistent table. /** Look up a persistent table.
@param id table ID @param id table ID
@return table @return table
@retval NULL if not cached */ @retval nullptr if not cached */
dict_table_t* get_table(table_id_t id) dict_table_t *find_table(table_id_t id)
{ {
mysql_mutex_assert_owner(&mutex); mysql_mutex_assert_owner(&mutex);
dict_table_t* table; dict_table_t *table;
ulint fold = ut_fold_ull(id); ulint fold = ut_fold_ull(id);
HASH_SEARCH(id_hash, &table_id_hash, fold, dict_table_t*, HASH_SEARCH(id_hash, &table_id_hash, fold, dict_table_t*, table,
table, ut_ad(table->cached), table->id == id);
ut_ad(table->cached), table->id == id); DBUG_ASSERT(!table || !table->is_temporary());
DBUG_ASSERT(!table || !table->is_temporary()); return table;
return table; }
}
bool is_initialised() const { return m_initialised; } bool is_initialised() const { return m_initialised; }
@@ -1480,14 +1506,13 @@ public:
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
/** Find a table */ /** Find a table */
template <bool in_lru> bool find(dict_table_t* table) template <bool in_lru> bool find(const dict_table_t *table)
{ {
ut_ad(table); ut_ad(table);
ut_ad(table->can_be_evicted == in_lru); ut_ad(table->can_be_evicted == in_lru);
mysql_mutex_assert_owner(&mutex); mysql_mutex_assert_owner(&mutex);
for (const dict_table_t* t = UT_LIST_GET_FIRST(in_lru for (const dict_table_t* t= in_lru ? table_LRU.start : table_non_LRU.start;
? table_LRU : table_non_LRU); t; t = UT_LIST_GET_NEXT(table_LRU, t))
t; t = UT_LIST_GET_NEXT(table_LRU, t))
{ {
if (t == table) return true; if (t == table) return true;
ut_ad(t->can_be_evicted == in_lru); ut_ad(t->can_be_evicted == in_lru);
@@ -1495,25 +1520,25 @@ public:
return false; return false;
} }
/** Find a table */ /** Find a table */
bool find(dict_table_t* table) bool find(const dict_table_t *table)
{ {
return table->can_be_evicted ? find<true>(table) : find<false>(table); return table->can_be_evicted ? find<true>(table) : find<false>(table);
} }
#endif #endif
/** Move a table to the non-LRU list from the LRU list. */ /** Move a table to the non-LRU list from the LRU list. */
void prevent_eviction(dict_table_t* table) void prevent_eviction(dict_table_t *table)
{ {
ut_ad(find(table)); ut_ad(find(table));
if (table->can_be_evicted) if (table->can_be_evicted)
{ {
table->can_be_evicted = FALSE; table->can_be_evicted= false;
UT_LIST_REMOVE(table_LRU, table); UT_LIST_REMOVE(table_LRU, table);
UT_LIST_ADD_LAST(table_non_LRU, table); UT_LIST_ADD_LAST(table_non_LRU, table);
} }
} }
/** Acquire a reference to a cached table. */ /** Acquire a reference to a cached table. */
inline void acquire(dict_table_t* table); inline void acquire(dict_table_t *table);
/** Assert that the mutex is locked */ /** Assert that the mutex is locked */
void assert_locked() const { mysql_mutex_assert_owner(&mutex); } void assert_locked() const { mysql_mutex_assert_owner(&mutex); }
@@ -1573,8 +1598,8 @@ public:
+ (sizeof(dict_col_t) + sizeof(dict_field_t)) * 10 + (sizeof(dict_col_t) + sizeof(dict_field_t)) * 10
+ sizeof(dict_field_t) * 5 /* total number of key fields */ + sizeof(dict_field_t) * 5 /* total number of key fields */
+ 200; /* arbitrary, covering names and overhead */ + 200; /* arbitrary, covering names and overhead */
size += (table_hash.n_cells + table_id_hash.n_cells size += (table_hash.n_cells + table_id_hash.n_cells +
+ temp_id_hash.n_cells) * sizeof(hash_cell_t); temp_id_hash.n_cells) * sizeof(hash_cell_t);
return size; return size;
} }
@@ -1582,12 +1607,43 @@ public:
@param half whether to consider half the tables only (instead of all) @param half whether to consider half the tables only (instead of all)
@return number of tables evicted */ @return number of tables evicted */
ulint evict_table_LRU(bool half); ulint evict_table_LRU(bool half);
/** Look up a table in the dictionary cache.
@param name table name
@return table handle
@retval nullptr if not found */
dict_table_t *find_table(const span<const char> &name) const
{
assert_locked();
for (dict_table_t *table= static_cast<dict_table_t*>
(HASH_GET_FIRST(&table_hash, table_hash.calc_hash
(ut_fold_binary(reinterpret_cast<const byte*>
(name.data()), name.size()))));
table; table= table->name_hash)
if (strlen(table->name.m_name) == name.size() &&
!memcmp(table->name.m_name, name.data(), name.size()))
return table;
return nullptr;
}
/** Look up or load a table definition
@param name table name
@param ignore errors to ignore when loading the table definition
@return table handle
@retval nullptr if not found */
dict_table_t *load_table(const span<const char> &name,
dict_err_ignore_t ignore= DICT_ERR_IGNORE_NONE);
/** Attempt to load the system tables on startup
@return whether any discrepancy with the expected definition was found */
bool load_sys_tables();
/** Create or check system tables on startup */
dberr_t create_or_check_sys_tables();
}; };
/** the data dictionary cache */ /** the data dictionary cache */
extern dict_sys_t dict_sys; extern dict_sys_t dict_sys;
#define dict_table_prevent_eviction(table) dict_sys.prevent_eviction(table)
#define dict_sys_lock() dict_sys.lock(SRW_LOCK_CALL) #define dict_sys_lock() dict_sys.lock(SRW_LOCK_CALL)
#define dict_sys_unlock() dict_sys.unlock() #define dict_sys_unlock() dict_sys.unlock()

View File

@@ -39,20 +39,6 @@ Created 4/24/1996 Heikki Tuuri
/** A stack of table names related through foreign key constraints */ /** A stack of table names related through foreign key constraints */
typedef std::deque<const char*, ut_allocator<const char*> > dict_names_t; typedef std::deque<const char*, ut_allocator<const char*> > dict_names_t;
/** enum that defines all system table IDs. @see SYSTEM_TABLE_NAME[] */
enum dict_system_id_t {
SYS_TABLES = 0,
SYS_INDEXES,
SYS_COLUMNS,
SYS_FIELDS,
SYS_FOREIGN,
SYS_FOREIGN_COLS,
SYS_VIRTUAL,
/* This must be last item. Defines the number of system tables. */
SYS_NUM_SYSTEM_TABLES
};
/** Check each tablespace found in the data dictionary. /** Check each tablespace found in the data dictionary.
Then look at each table defined in SYS_TABLES that has a space_id > 0 Then look at each table defined in SYS_TABLES that has a space_id > 0
to find all the file-per-table tablespaces. to find all the file-per-table tablespaces.
@@ -74,18 +60,6 @@ dict_get_and_save_data_dir_path(
dict_table_t* table, dict_table_t* table,
bool dict_mutex_own); bool dict_mutex_own);
/** 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.
@param[in] name Table name in the dbname/tablename format
@param[in] ignore_err Error to be ignored when loading
table and its index definition
@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 file_unreadable
flag in the table object we return. */
dict_table_t* dict_load_table(const char* name, dict_err_ignore_t ignore_err);
/***********************************************************************//** /***********************************************************************//**
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 */
@@ -140,7 +114,7 @@ dict_startscan_system(
btr_pcur_t* pcur, /*!< out: persistent cursor to btr_pcur_t* pcur, /*!< out: persistent cursor to
the record */ the record */
mtr_t* mtr, /*!< in: the mini-transaction */ mtr_t* mtr, /*!< in: the mini-transaction */
dict_system_id_t system_id); /*!< in: which system table to open */ dict_table_t* table); /*!< in: system table */
/********************************************************************//** /********************************************************************//**
This function get the next system table record as we scan the table. This function get the next system table record as we scan the table.
@return the record if found, NULL if end of scan. */ @return the record if found, NULL if end of scan. */
@@ -150,19 +124,18 @@ dict_getnext_system(
btr_pcur_t* pcur, /*!< in/out: persistent cursor btr_pcur_t* pcur, /*!< in/out: persistent cursor
to the record */ to the record */
mtr_t* mtr); /*!< in: the mini-transaction */ mtr_t* mtr); /*!< in: the mini-transaction */
/********************************************************************//**
This function processes one SYS_TABLES record and populate the dict_table_t /** Load a table definition from a SYS_TABLES record to dict_table_t.
struct for the table. Do not load any columns or indexes.
@return error message, or NULL on success */ @param[in] name Table name
const char* @param[in] rec SYS_TABLES record
dict_process_sys_tables_rec_and_mtr_commit( @param[out,own] table table, or nullptr
/*=======================================*/ @return error message
mem_heap_t* heap, /*!< in: temporary memory heap */ @retval nullptr on success */
const rec_t* rec, /*!< in: SYS_TABLES record */ const char *dict_load_table_low(const span<const char> &name,
dict_table_t** table, /*!< out: dict_table_t to fill */ const rec_t *rec, dict_table_t **table)
bool cached, /*!< in: whether to load from cache */ MY_ATTRIBUTE((nonnull, warn_unused_result));
mtr_t* mtr); /*!< in/out: mini-transaction,
will be committed */
/********************************************************************//** /********************************************************************//**
This function parses a SYS_INDEXES record and populate a dict_index_t This function parses a SYS_INDEXES record and populate a dict_index_t
structure with the information from the record. For detail information structure with the information from the record. For detail information

View File

@@ -28,10 +28,10 @@ Created 1/8/1996 Heikki Tuuri
#ifndef dict0mem_h #ifndef dict0mem_h
#define dict0mem_h #define dict0mem_h
#include "dict0types.h"
#include "data0type.h" #include "data0type.h"
#include "mem0mem.h" #include "mem0mem.h"
#include "row0types.h" #include "row0types.h"
#include "rem0types.h"
#include "btr0types.h" #include "btr0types.h"
#include "lock0types.h" #include "lock0types.h"
#include "que0types.h" #include "que0types.h"
@@ -298,17 +298,6 @@ parent table will fail, and user has to drop excessive foreign constraint
before proceeds. */ before proceeds. */
#define FK_MAX_CASCADE_DEL 15 #define FK_MAX_CASCADE_DEL 15
/** Create a table memory object.
@param name table name
@param space tablespace
@param n_cols total number of columns (both virtual and non-virtual)
@param n_v_cols number of virtual columns
@param flags table flags
@param flags2 table flags2
@return own: table object */
dict_table_t *dict_mem_table_create(const char *name, fil_space_t *space,
ulint n_cols, ulint n_v_cols, ulint flags,
ulint flags2);
/****************************************************************/ /** /****************************************************************/ /**
Free a table memory object. */ Free a table memory object. */
void void
@@ -1816,7 +1805,7 @@ typedef enum {
} dict_frm_t; } dict_frm_t;
/** Data structure for a database table. Most fields will be /** Data structure for a database table. Most fields will be
initialized to 0, NULL or FALSE in dict_mem_table_create(). */ zero-initialized in dict_table_t::create(). */
struct dict_table_t { struct dict_table_t {
/** Get reference count. /** Get reference count.
@@ -2435,10 +2424,24 @@ public:
return false; return false;
} }
/** Check whether the table name is same as mysql/innodb_stats_table /** @return whether the name is
or mysql/innodb_index_stats. mysql.innodb_index_stats or mysql.innodb_table_stats */
@return true if the table name is same as stats table */ inline bool is_stats_table() const;
bool is_stats_table() const;
/** Create metadata.
@param name table name
@param space tablespace
@param n_cols total number of columns (both virtual and non-virtual)
@param n_v_cols number of virtual columns
@param flags table flags
@param flags2 table flags2
@return newly allocated table object */
static dict_table_t *create(const span<const char> &name, fil_space_t *space,
ulint n_cols, ulint n_v_cols, ulint flags,
ulint flags2);
/** @return whether SYS_TABLES.NAME is for a '#sql-ib' table */
static bool is_garbage_name(const void *data, size_t size);
}; };
inline void dict_index_t::set_modified(mtr_t& mtr) const inline void dict_index_t::set_modified(mtr_t& mtr) const

View File

@@ -1,50 +0,0 @@
/*****************************************************************************
Copyright (c) 2010, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file include/dict0priv.h
Data dictionary private functions
Created Fri 2 Jul 2010 13:30:38 EST - Sunny Bains
*******************************************************/
#ifndef dict0priv_h
#define dict0priv_h
/**********************************************************************//**
Gets a table; loads it to the dictionary cache if necessary. A low-level
function. Note: Not to be called from outside dict0*c functions.
@return table, NULL if not found */
UNIV_INLINE
dict_table_t*
dict_table_get_low(
/*===============*/
const char* table_name); /*!< in: table name */
/**********************************************************************//**
Checks if a table is in the dictionary cache.
@return table, NULL if not found */
UNIV_INLINE
dict_table_t*
dict_table_check_if_in_cache_low(
/*=============================*/
const char* table_name); /*!< in: table name */
#include "dict0priv.ic"
#endif /* dict0priv.h */

View File

@@ -1,91 +0,0 @@
/*****************************************************************************
Copyright (c) 2010, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
*****************************************************************************/
/******************************************************************//**
@file include/dict0priv.ic
Data dictionary system private include file
Created Wed 13 Oct 2010 16:10:14 EST Sunny Bains
***********************************************************************/
#include "dict0dict.h"
#include "dict0load.h"
/**********************************************************************//**
Gets a table; loads it to the dictionary cache if necessary. A low-level
function.
@return table, NULL if not found */
UNIV_INLINE
dict_table_t*
dict_table_get_low(
/*===============*/
const char* table_name) /*!< in: table name */
{
dict_table_t* table;
ut_ad(table_name);
dict_sys.assert_locked();
table = dict_table_check_if_in_cache_low(table_name);
if (table && table->corrupted) {
ib::error error;
error << "Table " << table->name << "is corrupted";
if (srv_load_corrupted) {
error << ", but innodb_force_load_corrupted is set";
} else {
return(NULL);
}
}
if (table == NULL) {
table = dict_load_table(table_name, DICT_ERR_IGNORE_NONE);
}
ut_ad(!table || table->cached);
return(table);
}
/**********************************************************************//**
Checks if a table is in the dictionary cache.
@return table, NULL if not found */
UNIV_INLINE
dict_table_t*
dict_table_check_if_in_cache_low(
/*=============================*/
const char* table_name) /*!< in: table name */
{
dict_table_t* table;
ulint table_fold;
DBUG_ENTER("dict_table_check_if_in_cache_low");
DBUG_PRINT("dict_table_check_if_in_cache_low",
("table: '%s'", table_name));
ut_ad(table_name);
dict_sys.assert_locked();
/* Look for the table name in the hash table */
table_fold = ut_fold_string(table_name);
HASH_SEARCH(name_hash, &dict_sys.table_hash, table_fold,
dict_table_t*, table, ut_ad(table->cached),
!strcmp(table->name.m_name, table_name));
DBUG_RETURN(table);
}

View File

@@ -28,8 +28,11 @@ Created 1/8/1996 Heikki Tuuri
#define dict0types_h #define dict0types_h
#include "univ.i" #include "univ.i"
#include "span.h"
#include <rem0types.h> #include <rem0types.h>
using st_::span;
struct dict_col_t; struct dict_col_t;
struct dict_field_t; struct dict_field_t;
struct dict_index_t; struct dict_index_t;

View File

@@ -39,7 +39,6 @@ Created 10/25/1995 Heikki Tuuri
#include "log0recv.h" #include "log0recv.h"
#include "dict0types.h" #include "dict0types.h"
#include "ilist.h" #include "ilist.h"
#include "span.h"
#include <set> #include <set>
#include <mutex> #include <mutex>
@@ -1621,7 +1620,7 @@ char* fil_make_filepath(const char *path, const fil_space_t::name_type &name,
ib_extention ext, bool trim_name); ib_extention ext, bool trim_name);
char *fil_make_filepath(const char* path, const table_name_t name, char *fil_make_filepath(const char* path, const table_name_t name,
ib_extention ext, bool trim_name); ib_extention suffix, bool strip_name);
/** Create a tablespace file. /** Create a tablespace file.
@param[in] space_id Tablespace ID @param[in] space_id Tablespace ID
@@ -1677,7 +1676,7 @@ statement to update the dictionary tables if they are incorrect.
@param[in] purpose FIL_TYPE_TABLESPACE or FIL_TYPE_TEMPORARY @param[in] purpose FIL_TYPE_TABLESPACE or FIL_TYPE_TEMPORARY
@param[in] id tablespace ID @param[in] id tablespace ID
@param[in] flags expected FSP_SPACE_FLAGS @param[in] flags expected FSP_SPACE_FLAGS
@param[in] tablename table name @param[in] name table name
If file-per-table, it is the table name in the databasename/tablename format If file-per-table, it is the table name in the databasename/tablename format
@param[in] path_in expected filepath, usually read from dictionary @param[in] path_in expected filepath, usually read from dictionary
@param[out] err DB_SUCCESS or error code @param[out] err DB_SUCCESS or error code
@@ -1689,7 +1688,7 @@ fil_ibd_open(
fil_type_t purpose, fil_type_t purpose,
ulint id, ulint id,
ulint flags, ulint flags,
const table_name_t tablename, fil_space_t::name_type name,
const char* path_in, const char* path_in,
dberr_t* err = NULL) dberr_t* err = NULL)
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));

View File

@@ -501,7 +501,7 @@ public:
@param name table name @param name table name
@return filepath() @return filepath()
@retval nullptr if the .isl file does not exist or cannot be read */ @retval nullptr if the .isl file does not exist or cannot be read */
const char* open_link_file(const table_name_t& name); const char* open_link_file(const fil_space_t::name_type name);
/** Delete an InnoDB Symbolic Link (ISL) file. */ /** Delete an InnoDB Symbolic Link (ISL) file. */
void delete_link_file(void); void delete_link_file(void);

View File

@@ -377,25 +377,17 @@ row_create_index_for_mysql(
fil_encryption_t mode, /*!< in: encryption mode */ fil_encryption_t mode, /*!< in: encryption mode */
uint32_t key_id) /*!< in: encryption key_id */ uint32_t key_id) /*!< in: encryption key_id */
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
The master thread in srv0srv.cc calls this regularly to drop tables which /** The master task calls this regularly to drop tables which
we must drop in background after queries to them have ended. Such lazy we must drop in background after queries to them have ended.
dropping of tables is needed in ALTER TABLE on Unix.
@return how many tables dropped + remaining tables in list */ @return how many tables dropped + remaining tables in list */
ulint ulint row_drop_tables_for_mysql_in_background();
row_drop_tables_for_mysql_in_background(void);
/*=========================================*/ /** @return number of tables in the background drop list */
/*********************************************************************//** ulint row_get_background_drop_list_len_low();
Get the background drop list length. NOTE: the caller must own the kernel
mutex!
@return how many tables in list */
ulint
row_get_background_drop_list_len_low(void);
/*======================================*/
/** Drop garbage tables during recovery. */ /** Drop garbage tables during recovery. */
void void row_mysql_drop_garbage_tables();
row_mysql_drop_garbage_tables();
/*********************************************************************//** /*********************************************************************//**
Sets an exclusive lock on a table. Sets an exclusive lock on a table.

View File

@@ -964,7 +964,7 @@ public:
} }
/** @return whether the table has lock on /** @return whether the table has lock on
mysql.innodb_table_stats and mysql.innodb_index_stats */ mysql.innodb_table_stats or mysql.innodb_index_stats */
bool has_stats_table_lock() const; bool has_stats_table_lock() const;
/** Free the memory to trx_pools */ /** Free the memory to trx_pools */

View File

@@ -3857,7 +3857,7 @@ released:
LockMutexGuard g{SRW_LOCK_CALL}; LockMutexGuard g{SRW_LOCK_CALL};
for (const table_id_t id : to_evict) for (const table_id_t id : to_evict)
{ {
if (dict_table_t *table= dict_sys.get_table(id)) if (dict_table_t *table= dict_sys.find_table(id))
if (!table->get_ref_count() && !UT_LIST_GET_LEN(table->locks)) if (!table->get_ref_count() && !UT_LIST_GET_LEN(table->locks))
dict_sys.remove(table, true); dict_sys.remove(table, true);
} }

View File

@@ -1652,8 +1652,8 @@ page_zip_fields_decode(
return(NULL); return(NULL);
} }
table = dict_mem_table_create("ZIP_DUMMY", NULL, n, 0, table = dict_table_t::create({C_STRING_WITH_LEN("ZIP_DUMMY")},
DICT_TF_COMPACT, 0); nullptr, n, 0, DICT_TF_COMPACT, 0);
index = dict_mem_index_create(table, "ZIP_DUMMY", 0, n); index = dict_mem_index_create(table, "ZIP_DUMMY", 0, n);
index->n_uniq = static_cast<unsigned>(n) & dict_index_t::MAX_N_FIELDS; index->n_uniq = static_cast<unsigned>(n) & dict_index_t::MAX_N_FIELDS;
/* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */ /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */

View File

@@ -1783,8 +1783,9 @@ pars_create_table(
n_cols = que_node_list_get_len(column_defs); n_cols = que_node_list_get_len(column_defs);
table = dict_mem_table_create( table = dict_table_t::create(
table_sym->name, NULL, n_cols, 0, flags, flags2); {table_sym->name, strlen(table_sym->name)},
nullptr, n_cols, 0, flags, flags2);
mem_heap_t* heap = pars_sym_tab_global->heap; mem_heap_t* heap = pars_sym_tab_global->heap;
column = column_defs; column = column_defs;

View File

@@ -4091,7 +4091,10 @@ row_import_for_mysql(
ut_ad(!DICT_TF_HAS_DATA_DIR(table->flags) || table->data_dir_path); ut_ad(!DICT_TF_HAS_DATA_DIR(table->flags) || table->data_dir_path);
const char *data_dir_path = DICT_TF_HAS_DATA_DIR(table->flags) const char *data_dir_path = DICT_TF_HAS_DATA_DIR(table->flags)
? table->data_dir_path : nullptr; ? table->data_dir_path : nullptr;
filepath = fil_make_filepath(data_dir_path, table->name, IBD, fil_space_t::name_type name{
table->name.m_name, strlen(table->name.m_name)};
filepath = fil_make_filepath(data_dir_path, name, IBD,
data_dir_path != nullptr); data_dir_path != nullptr);
DBUG_EXECUTE_IF( DBUG_EXECUTE_IF(
@@ -4116,7 +4119,7 @@ row_import_for_mysql(
table->space = fil_ibd_open( table->space = fil_ibd_open(
true, FIL_TYPE_IMPORT, table->space_id, true, FIL_TYPE_IMPORT, table->space_id,
fsp_flags, table->name, filepath, &err); fsp_flags, name, filepath, &err);
ut_ad((table->space == NULL) == (err != DB_SUCCESS)); ut_ad((table->space == NULL) == (err != DB_SUCCESS));
DBUG_EXECUTE_IF("ib_import_open_tablespace_failure", DBUG_EXECUTE_IF("ib_import_open_tablespace_failure",

View File

@@ -36,7 +36,6 @@ Created 9/17/2000 Heikki Tuuri
#include "dict0crea.h" #include "dict0crea.h"
#include "dict0dict.h" #include "dict0dict.h"
#include "dict0load.h" #include "dict0load.h"
#include "dict0priv.h"
#include "dict0stats.h" #include "dict0stats.h"
#include "dict0stats_bg.h" #include "dict0stats_bg.h"
#include "dict0defrag_bg.h" #include "dict0defrag_bg.h"
@@ -2321,9 +2320,8 @@ row_create_table_for_mysql(
ib::error() << "Trying to create a MySQL system table " ib::error() << "Trying to create a MySQL system table "
<< table->name << " of type InnoDB. MySQL system" << table->name << " of type InnoDB. MySQL system"
" tables must be of the MyISAM type!"; " tables must be of the MyISAM type!";
#ifndef DBUG_OFF
err_exit: err_exit:
#endif /* !DBUG_OFF */
dict_mem_table_free(table); dict_mem_table_free(table);
trx->op_info = ""; trx->op_info = "";
@@ -2331,6 +2329,11 @@ err_exit:
return(DB_ERROR); return(DB_ERROR);
} }
if (!dict_sys.sys_tables_exist()) {
ib::error() << "Some InnoDB system tables are missing";
goto err_exit;
}
trx_start_if_not_started_xa(trx, true); trx_start_if_not_started_xa(trx, true);
heap = mem_heap_create(512); heap = mem_heap_create(512);
@@ -2622,10 +2625,8 @@ row_get_background_drop_list_len_low(void)
} }
/** Drop garbage tables during recovery. */ /** Drop garbage tables during recovery. */
void void row_mysql_drop_garbage_tables()
row_mysql_drop_garbage_tables()
{ {
mem_heap_t* heap = mem_heap_create(FN_REFLEN);
btr_pcur_t pcur; btr_pcur_t pcur;
mtr_t mtr; mtr_t mtr;
trx_t* trx = trx_create(); trx_t* trx = trx_create();
@@ -2641,7 +2642,6 @@ row_mysql_drop_garbage_tables()
const rec_t* rec; const rec_t* rec;
const byte* field; const byte* field;
ulint len; ulint len;
const char* table_name;
btr_pcur_move_to_next_user_rec(&pcur, &mtr); btr_pcur_move_to_next_user_rec(&pcur, &mtr);
@@ -2655,38 +2655,37 @@ row_mysql_drop_garbage_tables()
} }
field = rec_get_nth_field_old(rec, 0/*NAME*/, &len); field = rec_get_nth_field_old(rec, 0/*NAME*/, &len);
if (len == UNIV_SQL_NULL || len == 0) { if (len == UNIV_SQL_NULL) {
/* Corrupted SYS_TABLES.NAME */ /* Corrupted SYS_TABLES.NAME */
continue; continue;
} }
table_name = mem_heap_strdupl( if (!dict_table_t::is_garbage_name(field, len)) {
heap, continue;
reinterpret_cast<const char*>(field), len);
if (strstr(table_name, "/" TEMP_FILE_PREFIX_INNODB)) {
btr_pcur_store_position(&pcur, &mtr);
btr_pcur_commit_specify_mtr(&pcur, &mtr);
if (dict_load_table(table_name,
DICT_ERR_IGNORE_DROP)) {
row_drop_table_for_mysql(table_name, trx,
SQLCOM_DROP_TABLE);
trx_commit_for_mysql(trx);
}
mtr.start();
btr_pcur_restore_position(BTR_SEARCH_LEAF,
&pcur, &mtr);
} }
mem_heap_empty(heap); btr_pcur_store_position(&pcur, &mtr);
btr_pcur_commit_specify_mtr(&pcur, &mtr);
const span<const char> name = {
reinterpret_cast<const char*>(pcur.old_rec), len
};
if (dict_sys.load_table(name, DICT_ERR_IGNORE_DROP)) {
char* table_name = mem_strdupl(name.data(), len);
row_drop_table_for_mysql(table_name, trx,
SQLCOM_DROP_TABLE);
ut_free(table_name);
trx_commit_for_mysql(trx);
}
mtr.start();
btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
} }
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
mtr.commit(); mtr.commit();
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
trx->free(); trx->free();
mem_heap_free(heap);
} }
/*********************************************************************//** /*********************************************************************//**
@@ -3160,38 +3159,6 @@ row_drop_ancillary_fts_tables(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
/** Drop a table from the memory cache as part of dropping a table.
@param[in] tablename A copy of table->name. Used when table == null
@param[in,out] table Table cache entry
@param[in,out] trx Transaction handle
@return error code or DB_SUCCESS */
UNIV_INLINE
dberr_t
row_drop_table_from_cache(
const char* tablename,
dict_table_t* table,
trx_t* trx)
{
dberr_t err = DB_SUCCESS;
ut_ad(!table->is_temporary());
/* Remove the pointer to this table object from the list
of modified tables by the transaction because the object
is going to be destroyed below. */
trx->mod_tables.erase(table);
dict_sys.remove(table);
if (dict_load_table(tablename, DICT_ERR_IGNORE_FK_NOKEY)) {
ib::error() << "Not able to remove table "
<< ut_get_name(trx, tablename)
<< " from the dictionary cache!";
err = DB_ERROR;
}
return(err);
}
/** Drop a table for MySQL. /** Drop a table for MySQL.
If the data dictionary was not already locked by the transaction, If the data dictionary was not already locked by the transaction,
the transaction will be committed. Otherwise, the data dictionary the transaction will be committed. Otherwise, the data dictionary
@@ -3331,7 +3298,7 @@ row_drop_table_for_mysql(
} }
} }
dict_table_prevent_eviction(table); dict_sys.prevent_eviction(table);
dict_table_close(table, TRUE, FALSE); dict_table_close(table, TRUE, FALSE);
/* Check if the table is referenced by foreign key constraints from /* Check if the table is referenced by foreign key constraints from
@@ -3475,10 +3442,8 @@ defer:
pars_info_add_str_literal(info, "name", name); pars_info_add_str_literal(info, "name", name);
if (sqlcom != SQLCOM_TRUNCATE if (sqlcom != SQLCOM_TRUNCATE && strchr(name, '/')
&& strchr(name, '/') && dict_sys.sys_foreign && dict_sys.sys_foreign_cols) {
&& dict_table_get_low("SYS_FOREIGN")
&& dict_table_get_low("SYS_FOREIGN_COLS")) {
err = que_eval_sql( err = que_eval_sql(
info, info,
"PROCEDURE DROP_FOREIGN_PROC () IS\n" "PROCEDURE DROP_FOREIGN_PROC () IS\n"
@@ -3507,7 +3472,7 @@ defer:
} }
} else { } else {
do_drop: do_drop:
if (dict_table_get_low("SYS_VIRTUAL")) { if (dict_sys.sys_virtual) {
err = que_eval_sql( err = que_eval_sql(
info, info,
"PROCEDURE DROP_VIRTUAL_PROC () IS\n" "PROCEDURE DROP_VIRTUAL_PROC () IS\n"
@@ -3588,12 +3553,8 @@ do_drop:
IBD, IBD,
table->data_dir_path != nullptr); table->data_dir_path != nullptr);
/* Free the dict_table_t object. */ trx->mod_tables.erase(table);
err = row_drop_table_from_cache(tablename, table, trx); dict_sys.remove(table);
if (err != DB_SUCCESS) {
ut_free(filepath);
break;
}
/* Do not attempt to drop known-to-be-missing tablespaces, /* Do not attempt to drop known-to-be-missing tablespaces,
nor the system tablespace. */ nor the system tablespace. */
@@ -4136,8 +4097,8 @@ row_rename_table_for_mysql(
dict_mem_table_fill_foreign_vcol_set(table); dict_mem_table_fill_foreign_vcol_set(table);
while (!fk_tables.empty()) { while (!fk_tables.empty()) {
dict_load_table(fk_tables.front(), const char *f = fk_tables.front();
DICT_ERR_IGNORE_NONE); dict_sys.load_table({f, strlen(f)});
fk_tables.pop_front(); fk_tables.pop_front();
} }

View File

@@ -428,10 +428,10 @@ static bool row_undo_ins_parse_undo_rec(undo_node_t* node, bool dict_locked)
DICT_TABLE_OP_NORMAL); DICT_TABLE_OP_NORMAL);
} else if (!dict_locked) { } else if (!dict_locked) {
dict_sys.mutex_lock(); dict_sys.mutex_lock();
node->table = dict_sys.get_temporary_table(table_id); node->table = dict_sys.acquire_temporary_table(table_id);
dict_sys.mutex_unlock(); dict_sys.mutex_unlock();
} else { } else {
node->table = dict_sys.get_temporary_table(table_id); node->table = dict_sys.acquire_temporary_table(table_id);
} }
if (!node->table) { if (!node->table) {

View File

@@ -1256,10 +1256,10 @@ static bool row_undo_mod_parse_undo_rec(undo_node_t* node, bool dict_locked)
DICT_TABLE_OP_NORMAL); DICT_TABLE_OP_NORMAL);
} else if (!dict_locked) { } else if (!dict_locked) {
dict_sys.mutex_lock(); dict_sys.mutex_lock();
node->table = dict_sys.get_temporary_table(table_id); node->table = dict_sys.acquire_temporary_table(table_id);
dict_sys.mutex_unlock(); dict_sys.mutex_unlock();
} else { } else {
node->table = dict_sys.get_temporary_table(table_id); node->table = dict_sys.acquire_temporary_table(table_id);
} }
if (!node->table) { if (!node->table) {

View File

@@ -1454,6 +1454,7 @@ file_checked:
if (srv_operation == SRV_OPERATION_RESTORE) { if (srv_operation == SRV_OPERATION_RESTORE) {
break; break;
} }
dict_sys.load_sys_tables();
trx_lists_init_at_db_start(); trx_lists_init_at_db_start();
break; break;
case SRV_OPERATION_RESTORE_DELTA: case SRV_OPERATION_RESTORE_DELTA:
@@ -1796,11 +1797,7 @@ skip_monitors:
} }
} }
/* Create the SYS_FOREIGN and SYS_FOREIGN_COLS system tables */ err = dict_sys.create_or_check_sys_tables();
err = dict_create_or_check_foreign_constraint_tables();
if (err == DB_SUCCESS) {
err = dict_create_or_check_sys_virtual();
}
switch (err) { switch (err) {
case DB_SUCCESS: case DB_SUCCESS:
break; break;

View File

@@ -703,7 +703,6 @@ static my_bool trx_rollback_recovered_callback(rw_trx_hash_element_t *element,
return 0; return 0;
} }
/** /**
Rollback any incomplete transactions which were encountered in crash recovery. Rollback any incomplete transactions which were encountered in crash recovery.

View File

@@ -2214,16 +2214,3 @@ trx_set_rw_mode(
trx->read_view.set_creator_trx_id(trx->id); trx->read_view.set_creator_trx_id(trx->id);
} }
} }
bool trx_t::has_stats_table_lock() const
{
for (lock_list::const_iterator it= lock.table_locks.begin(),
end= lock.table_locks.end(); it != end; ++it)
{
const lock_t *lock= *it;
if (lock && lock->un_member.tab_lock.table->is_stats_table())
return true;
}
return false;
}