summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/innodb/r/row_format_redundant.result15
-rw-r--r--mysql-test/suite/innodb/t/row_format_redundant.test97
-rw-r--r--storage/innobase/dict/dict0load.cc89
-rw-r--r--storage/innobase/fts/fts0fts.cc19
4 files changed, 125 insertions, 95 deletions
diff --git a/mysql-test/suite/innodb/r/row_format_redundant.result b/mysql-test/suite/innodb/r/row_format_redundant.result
index c6926872d1a..45dfdf01218 100644
--- a/mysql-test/suite/innodb/r/row_format_redundant.result
+++ b/mysql-test/suite/innodb/r/row_format_redundant.result
@@ -1,7 +1,9 @@
+SET GLOBAL innodb_file_per_table=1;
#
# Bug#21644827 - FTS, ASSERT !SRV_READ_ONLY_MODE || M_IMPL.M_LOG_MODE ==
# MTR_LOG_NO_REDO
#
+SET GLOBAL innodb_file_per_table=ON;
create table t1 (a int not null, d varchar(15) not null, b
varchar(198) not null, c char(156),
fulltext ftsic(c)) engine=InnoDB
@@ -49,6 +51,9 @@ ERROR HY000: Table 't3' is read only
TRUNCATE TABLE t1;
TRUNCATE TABLE t2;
TRUNCATE TABLE t3;
+corrupted SYS_TABLES.MIX_LEN for test/t1
+corrupted SYS_TABLES.MIX_LEN for test/t2
+corrupted SYS_TABLES.MIX_LEN for test/t3
TRUNCATE TABLE t1;
ERROR 42S02: Table 'test.t1' doesn't exist in engine
TRUNCATE TABLE t2;
@@ -66,9 +71,9 @@ ERROR HY000: Error on rename of './test/t1' to './test/tee_one' (errno: 155 "The
DROP TABLE t1;
Warnings:
Warning 1932 Table 'test.t1' doesn't exist in engine
-NOT FOUND /\[ERROR\] InnoDB: Table `test`\.`t1` in InnoDB data dictionary contains invalid flags. SYS_TABLES.MIX_LEN=255;/ in mysqld.1.err
-FOUND 48 /\[ERROR\] InnoDB: InnoDB: Error: table unused flags are:255/ in mysqld.1.err
-FOUND 1 /\[Warning\] InnoDB: Parent table of FTS auxiliary table test/FTS_.* not found\./ in mysqld.1.err
-NOT FOUND /"\[Warning\] InnoDB: Cannot open table test/t1 from the internal data dictionary of InnoDB though the \.frm file for the table exists.";/ in mysqld.1.err
-FOUND 2 /\[ERROR\] InnoDB: Table `test`.`t1` does not exist in the InnoDB internal data dictionary though MariaDB is trying to (drop|rename)/ in mysqld.1.err
DROP TABLE t2,t3;
+FOUND 49 /\[ERROR\] InnoDB: Table `test`\.`t1` in InnoDB data dictionary contains invalid flags\. SYS_TABLES.MIX_LEN=255\b/ in mysqld.1.err
+ib_buffer_pool
+ib_logfile0
+ib_logfile1
+ibdata1
diff --git a/mysql-test/suite/innodb/t/row_format_redundant.test b/mysql-test/suite/innodb/t/row_format_redundant.test
index 4d41314fc79..04f17ca0d63 100644
--- a/mysql-test/suite/innodb/t/row_format_redundant.test
+++ b/mysql-test/suite/innodb/t/row_format_redundant.test
@@ -1,13 +1,37 @@
---source include/innodb_page_size.inc
---source include/have_debug.inc
+--source include/have_innodb.inc
# Embedded mode doesn't allow restarting
--source include/not_embedded.inc
+--disable_query_log
+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.MIX_LEN=255");
+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: Table `test`.`t1` does not exist in the InnoDB internal data dictionary though MariaDB is trying to (rename|drop)");
+FLUSH TABLES;
+--enable_query_log
+
+let INNODB_PAGE_SIZE=`select @@innodb_page_size`;
+let MYSQLD_DATADIR=`select @@datadir`;
+
+let bugdir= $MYSQLTEST_VARDIR/tmp/row_format_redundant;
+--mkdir $bugdir
+--let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.1.err
+
+--let $d=--innodb-data-home-dir=$bugdir --innodb-log-group-home-dir=$bugdir
+--let $d=$d --innodb-data-file-path=ibdata1:1M:autoextend
+--let $d=$d --innodb-undo-tablespaces=0 --innodb-stats-persistent=0
+--let $restart_parameters= $d
+--source include/restart_mysqld.inc
+
+SET GLOBAL innodb_file_per_table=1;
+
--echo #
--echo # Bug#21644827 - FTS, ASSERT !SRV_READ_ONLY_MODE || M_IMPL.M_LOG_MODE ==
--echo # MTR_LOG_NO_REDO
--echo #
+SET GLOBAL innodb_file_per_table=ON;
create table t1 (a int not null, d varchar(15) not null, b
varchar(198) not null, c char(156),
fulltext ftsic(c)) engine=InnoDB
@@ -45,7 +69,7 @@ insert into t3 values(555, 'eeee', 'ccccc', 'aaaaa');
# read-only restart requires the change buffer to be empty; therefore we
# do a slow shutdown.
SET GLOBAL innodb_fast_shutdown=0;
---let $restart_parameters = --innodb-read-only
+--let $restart_parameters= $d --innodb-read-only
--source include/restart_mysqld.inc
SELECT COUNT(*) FROM t1;
@@ -59,7 +83,7 @@ TRUNCATE TABLE t2;
--error ER_OPEN_AS_READONLY
TRUNCATE TABLE t3;
---let $restart_parameters =
+--let $restart_parameters= $d
--source include/restart_mysqld.inc
TRUNCATE TABLE t1;
@@ -67,9 +91,43 @@ TRUNCATE TABLE t2;
TRUNCATE TABLE t3;
--source include/shutdown_mysqld.inc
+--perl
+use strict;
+my $ps= $ENV{INNODB_PAGE_SIZE};
+my $file= "$ENV{bugdir}/ibdata1";
+open(FILE, "+<", $file) || die "Unable to open $file\n";
+# Read DICT_HDR_TABLES, the root page number of CLUST_IND (SYS_TABLES.NAME).
+sysseek(FILE, 7*$ps+38+32, 0) || die "Unable to seek $file";
+die "Unable to read $file" unless sysread(FILE, $_, 4) == 4;
+my $sys_tables_root = unpack("N", $_);
+my $page;
+sysseek(FILE, $sys_tables_root*$ps, 0) || die "Unable to seek $file";
+die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
+for (my $offset= 0x65; $offset;
+ $offset= unpack("n", substr($page,$offset-2,2)))
+{
+ my $n_fields= unpack("n", substr($page,$offset-4,2)) >> 1 & 0x3ff;
+ my $start= 0;
+ my $end= unpack("C", substr($page, $offset-7, 1));
+ my $name= substr($page,$offset+$start,$end-$start);
+ for (my $i= 0; $i < $n_fields; $i++) {
+ my $end= unpack("C", substr($page, $offset-7-$i, 1));
+ # Corrupt SYS_TABLES.MIX_LEN (ignored for ROW_FORMAT=REDUNDANT)
+ if ($i == 7 && $name =~ '^test/t[123]')
+ {
+ print "corrupted SYS_TABLES.MIX_LEN for $name\n";
+ substr($page,$offset+$start,$end-$start)= pack("N", 255);
+ }
+ $start= $end & 0x7f;
+ }
+}
+substr($page,0,4)=pack("N",0xdeadbeef);
+substr($page,$ps-8,4)=pack("N",0xdeadbeef);
+sysseek(FILE, $sys_tables_root*$ps, 0) || die "Unable to seek $file";
+syswrite(FILE, $page, $ps)==$ps || die "Unable to write $file\n";
+close(FILE) || die "Unable to close $file\n";
+EOF
-# FIXME: Corrupt the SYS_TABLES.TYPE of the tables, do not use --debug
---let $restart_parameters = --debug=d,ib_table_invalid_flags
--source include/start_mysqld.inc
--error ER_NO_SUCH_TABLE_IN_ENGINE
TRUNCATE TABLE t1;
@@ -82,25 +140,14 @@ SELECT COUNT(*) FROM t3;
--error ER_ERROR_ON_RENAME
RENAME TABLE t1 TO tee_one;
DROP TABLE t1;
+DROP TABLE t2,t3;
---disable_query_log
-call mtr.add_suppression("\\[ERROR\\] InnoDB: Table `test`\\.`t1` in InnoDB data dictionary contains invalid flags\\. SYS_TABLES\\.MIX_LEN=255");
-call mtr.add_suppression("\\[ERROR\\] InnoDB: InnoDB: Error: table unused flags are:255");
-call mtr.add_suppression("\\[Warning\\] InnoDB: Parent table of FTS auxiliary table test/FTS_.* not found\\.");
-call mtr.add_suppression("\\[Warning\\] InnoDB: Cannot open table test/t1 from the internal data dictionary of InnoDB though the \\.frm file for the table exists.");
-call mtr.add_suppression("\\[ERROR\\] InnoDB: Table `test`.`t1` does not exist in the InnoDB internal data dictionary though MariaDB is trying to (drop|rename)");
-
---enable_query_log
-let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err;
---let SEARCH_PATTERN= \[ERROR\] InnoDB: Table `test`\.`t1` in InnoDB data dictionary contains invalid flags. SYS_TABLES.MIX_LEN=255;
---source include/search_pattern_in_file.inc
---let SEARCH_PATTERN= \[ERROR\] InnoDB: InnoDB: Error: table unused flags are:255
---source include/search_pattern_in_file.inc
---let SEARCH_PATTERN= \[Warning\] InnoDB: Parent table of FTS auxiliary table test/FTS_.* not found\.
---source include/search_pattern_in_file.inc
---let SEARCH_PATTERN= "\\[Warning\\] InnoDB: Cannot open table test/t1 from the internal data dictionary of InnoDB though the \.frm file for the table exists.";
---source include/search_pattern_in_file.inc
---let SEARCH_PATTERN= \[ERROR\] InnoDB: Table `test`.`t1` does not exist in the InnoDB internal data dictionary though MariaDB is trying to (drop|rename)
+--let SEARCH_PATTERN= \[ERROR\] InnoDB: Table `test`\.`t1` in InnoDB data dictionary contains invalid flags\. SYS_TABLES.MIX_LEN=255\b
--source include/search_pattern_in_file.inc
-DROP TABLE t2,t3;
+--let $restart_parameters=
+--source include/restart_mysqld.inc
+
+--list_files $bugdir
+--remove_files_wildcard $bugdir
+--rmdir $bugdir
diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc
index ba1fbc5eb5d..0ca9ebfc622 100644
--- a/storage/innobase/dict/dict0load.cc
+++ b/storage/innobase/dict/dict0load.cc
@@ -185,17 +185,6 @@ dict_load_field_low(
for temporary storage */
const rec_t* rec); /*!< in: SYS_FIELDS record */
-/** 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(table_name_t& name, const rec_t* rec, dict_table_t** table);
-
/* If this flag is TRUE, then we will load the cluster index's (and tables')
metadata even if it is marked as "corrupted". */
my_bool srv_load_corrupted;
@@ -1149,6 +1138,7 @@ dict_sys_tablespaces_rec_read(
@param[out] flags Pointer to table flags
@param[out] flags2 Pointer to table flags2
@return true if the record was read correctly, false if not. */
+MY_ATTRIBUTE((warn_unused_result))
static
bool
dict_sys_tables_rec_read(
@@ -1164,8 +1154,6 @@ dict_sys_tables_rec_read(
ulint len;
ulint type;
- *flags2 = 0;
-
field = rec_get_nth_field_old(
rec, DICT_FLD__SYS_TABLES__ID, &len);
ut_ad(len == 8);
@@ -1202,22 +1190,40 @@ dict_sys_tables_rec_read(
" data dictionary contains invalid flags."
" SYS_TABLES.TYPE=" << type <<
" SYS_TABLES.N_COLS=" << *n_cols;
- *flags = ULINT_UNDEFINED;
return(false);
}
*flags = dict_sys_tables_type_to_tf(type, *n_cols);
- /* Get flags2 from SYS_TABLES.MIX_LEN */
- field = rec_get_nth_field_old(
- rec, DICT_FLD__SYS_TABLES__MIX_LEN, &len);
- *flags2 = mach_read_from_4(field);
+ /* For tables created before MySQL 4.1, there may be
+ garbage in SYS_TABLES.MIX_LEN where flags2 are found. Such tables
+ would always be in ROW_FORMAT=REDUNDANT which do not have the
+ high bit set in n_cols, and flags would be zero.
+ MySQL 4.1 was the first version to support innodb_file_per_table,
+ that is, *space_id != 0. */
+ if (*flags != 0 || *space_id != 0 || *n_cols & DICT_N_COLS_COMPACT) {
- /* DICT_TF2_FTS will be set when indexes are being loaded */
- *flags2 &= ~DICT_TF2_FTS;
+ /* Get flags2 from SYS_TABLES.MIX_LEN */
+ field = rec_get_nth_field_old(
+ rec, DICT_FLD__SYS_TABLES__MIX_LEN, &len);
+ *flags2 = mach_read_from_4(field);
+
+ if (!dict_tf2_is_valid(*flags, *flags2)) {
+ ib::error() << "Table " << table_name << " in InnoDB"
+ " data dictionary contains invalid flags."
+ " SYS_TABLES.MIX_LEN=" << *flags2;
+ return(false);
+ }
+
+ /* DICT_TF2_FTS will be set when indexes are being loaded */
+ *flags2 &= ~DICT_TF2_FTS;
+
+ /* Now that we have used this bit, unset it. */
+ *n_cols &= ~DICT_N_COLS_COMPACT;
+ } else {
+ *flags2 = 0;
+ }
- /* Now that we have used this bit, unset it. */
- *n_cols &= ~DICT_N_COLS_COMPACT;
return(true);
}
@@ -1280,11 +1286,10 @@ dict_check_sys_tables(
("name: %p, '%s'", table_name.m_name,
table_name.m_name));
- dict_sys_tables_rec_read(rec, table_name,
- &table_id, &space_id,
- &n_cols, &flags, &flags2);
- if (flags == ULINT_UNDEFINED
- || is_system_tablespace(space_id)) {
+ if (!dict_sys_tables_rec_read(rec, table_name,
+ &table_id, &space_id,
+ &n_cols, &flags, &flags2)
+ || space_id == TRX_SYS_SPACE) {
ut_free(table_name.m_name);
continue;
}
@@ -2091,6 +2096,8 @@ func_exit:
static const char* dict_load_index_del = "delete-marked record in SYS_INDEXES";
/** Error message for table->id mismatch in dict_load_index_low() */
static const char* dict_load_index_id_err = "SYS_INDEXES.TABLE_ID mismatch";
+/** Error message for SYS_TABLES flags mismatch in dict_load_table_low() */
+static const char* dict_load_table_flags = "incorrect flags in SYS_TABLES";
/** 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
@@ -2539,11 +2546,9 @@ dict_load_table_low(table_name_t& name, const rec_t* rec, dict_table_t** table)
return(error_text);
}
- dict_sys_tables_rec_read(rec, name, &table_id, &space_id,
- &t_num, &flags, &flags2);
-
- if (flags == ULINT_UNDEFINED) {
- return("incorrect flags in SYS_TABLES");
+ if (!dict_sys_tables_rec_read(rec, name, &table_id, &space_id,
+ &t_num, &flags, &flags2)) {
+ return(dict_load_table_flags);
}
dict_table_decode_n_col(t_num, &n_cols, &n_v_col);
@@ -2857,8 +2862,9 @@ err_exit:
err_msg = dict_load_table_low(name, rec, &table);
if (err_msg) {
-
- ib::error() << err_msg;
+ if (err_msg != dict_load_table_flags) {
+ ib::error() << err_msg;
+ }
goto err_exit;
}
@@ -2914,21 +2920,6 @@ err_exit:
}
}
- /* We don't trust the table->flags2(retrieved from SYS_TABLES.MIX_LEN
- field) if the datafiles are from 3.23.52 version. To identify this
- version, we do the below check and reset the flags. */
- if (!DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
- && table->space == srv_sys_space.space_id()
- && table->flags == 0) {
- table->flags2 = 0;
- }
-
- DBUG_EXECUTE_IF("ib_table_invalid_flags",
- if(strcmp(table->name.m_name, "test/t1") == 0) {
- table->flags2 = 255;
- table->flags = 255;
- });
-
if (!dict_tf2_is_valid(table->flags, table->flags2)) {
ib::error() << "Table " << table->name << " in InnoDB"
" data dictionary contains invalid flags."
diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc
index 1cce58dd9c5..60cc3c91fef 100644
--- a/storage/innobase/fts/fts0fts.cc
+++ b/storage/innobase/fts/fts0fts.cc
@@ -1715,21 +1715,6 @@ fts_drop_tables(
return(error);
}
-/** Extract only the required flags from table->flags2 for FTS Aux
-tables.
-@param[in] in_flags2 Table flags2
-@return extracted flags2 for FTS aux tables */
-static inline
-ulint
-fts_get_table_flags2_for_aux_tables(
- ulint flags2)
-{
- /* Extract the file_per_table flag & temporary file flag
- from the main FTS table flags2 */
- return((flags2 & DICT_TF2_USE_FILE_PER_TABLE) |
- (flags2 & DICT_TF2_TEMPORARY));
-}
-
/** Create dict_table_t object for FTS Aux tables.
@param[in] aux_table_name FTS Aux table name
@param[in] table table object of FTS Index
@@ -1744,7 +1729,9 @@ fts_create_in_mem_aux_table(
{
dict_table_t* new_table = dict_mem_table_create(
aux_table_name, table->space, n_cols, 0, table->flags,
- fts_get_table_flags2_for_aux_tables(table->flags2));
+ table->space == TRX_SYS_SPACE
+ ? 0 : table->space == SRV_TMP_SPACE_ID
+ ? DICT_TF2_TEMPORARY : DICT_TF2_USE_FILE_PER_TABLE);
if (DICT_TF_HAS_DATA_DIR(table->flags)) {
ut_ad(table->data_dir_path != NULL);