Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
383f77cd
Commit
383f77cd
authored
May 19, 2021
by
Marko Mäkelä
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Cleanup: Simplify dict_table_schema_check()
parent
7ff9e583
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
332 additions
and
580 deletions
+332
-580
mysql-test/suite/innodb/r/innodb_stats_fetch_corrupted.result
...l-test/suite/innodb/r/innodb_stats_fetch_corrupted.result
+17
-4
mysql-test/suite/innodb/t/innodb_stats_fetch_corrupted.test
mysql-test/suite/innodb/t/innodb_stats_fetch_corrupted.test
+12
-4
storage/innobase/dict/dict0dict.cc
storage/innobase/dict/dict0dict.cc
+0
-219
storage/innobase/dict/dict0stats.cc
storage/innobase/dict/dict0stats.cc
+303
-185
storage/innobase/include/data0type.h
storage/innobase/include/data0type.h
+0
-13
storage/innobase/include/data0type.ic
storage/innobase/include/data0type.ic
+0
-97
storage/innobase/include/dict0dict.h
storage/innobase/include/dict0dict.h
+0
-58
No files found.
mysql-test/suite/innodb/r/innodb_stats_fetch_corrupted.result
View file @
383f77cd
call mtr.add_suppression("InnoDB:
Table `mysql`.`innodb_index_stats` not found
");
call mtr.add_suppression("InnoDB: Fetch of persistent statistics requested for table
.*
");
call mtr.add_suppression("InnoDB:
Column stat_value in table mysql\\.innodb_index_stats is BIGINT UNSIGNED but should be BIGINT UNSIGNED NOT NULL
");
call mtr.add_suppression("InnoDB: Fetch of persistent statistics requested for table");
CREATE TABLE test_ps_fetch_corrupted
(a INT, PRIMARY KEY (a))
ENGINE=INNODB STATS_PERSISTENT=1;
...
...
@@ -17,7 +17,21 @@ FROM mysql.innodb_table_stats WHERE table_name = 'test_ps_fetch_corrupted';
n_rows 0
clustered_index_size 1
sum_of_other_index_sizes 0
ALTER TABLE mysql.innodb_index_stats RENAME TO mysql.innodb_index_stats_;
ALTER TABLE mysql.innodb_index_stats MODIFY stat_value BIGINT UNSIGNED NULL;
FLUSH TABLE test_ps_fetch_corrupted;
SELECT seq_in_index, column_name, cardinality
FROM information_schema.statistics WHERE table_name = 'test_ps_fetch_corrupted'
ORDER BY index_name, seq_in_index;
seq_in_index 1
column_name a
cardinality 0
SELECT table_rows, avg_row_length, max_data_length, index_length
FROM information_schema.tables WHERE table_name = 'test_ps_fetch_corrupted';
table_rows 0
avg_row_length 0
max_data_length 0
index_length 0
ALTER TABLE mysql.innodb_index_stats MODIFY stat_value BIGINT UNSIGNED NOT NULL;
FLUSH TABLE test_ps_fetch_corrupted;
SELECT seq_in_index, column_name, cardinality
FROM information_schema.statistics WHERE table_name = 'test_ps_fetch_corrupted'
...
...
@@ -31,6 +45,5 @@ table_rows 0
avg_row_length 0
max_data_length 0
index_length 0
ALTER TABLE mysql.innodb_index_stats_ RENAME TO mysql.innodb_index_stats;
DROP TABLE test_ps_fetch_corrupted;
# restart
mysql-test/suite/innodb/t/innodb_stats_fetch_corrupted.test
View file @
383f77cd
...
...
@@ -10,8 +10,8 @@
# server restart
--
source
include
/
not_embedded
.
inc
call
mtr
.
add_suppression
(
"InnoDB:
Table `mysql`.`innodb_index_stats` not found
"
);
call
mtr
.
add_suppression
(
"InnoDB: Fetch of persistent statistics requested for table
.*
"
);
call
mtr
.
add_suppression
(
"InnoDB:
Column stat_value in table mysql
\\
.innodb_index_stats is BIGINT UNSIGNED but should be BIGINT UNSIGNED NOT NULL
"
);
call
mtr
.
add_suppression
(
"InnoDB: Fetch of persistent statistics requested for table"
);
--
vertical_results
...
...
@@ -27,7 +27,7 @@ SELECT n_rows, clustered_index_size, sum_of_other_index_sizes
FROM
mysql
.
innodb_table_stats
WHERE
table_name
=
'test_ps_fetch_corrupted'
;
# corrupt the persistent storage
ALTER
TABLE
mysql
.
innodb_index_stats
RENAME
TO
mysql
.
innodb_index_stats_
;
ALTER
TABLE
mysql
.
innodb_index_stats
MODIFY
stat_value
BIGINT
UNSIGNED
NULL
;
# reopen the table, this will attept to read from the persistent storage
FLUSH
TABLE
test_ps_fetch_corrupted
;
...
...
@@ -42,7 +42,15 @@ SELECT table_rows, avg_row_length, max_data_length, index_length
FROM
information_schema
.
tables
WHERE
table_name
=
'test_ps_fetch_corrupted'
;
# restore the persistent storage
ALTER
TABLE
mysql
.
innodb_index_stats_
RENAME
TO
mysql
.
innodb_index_stats
;
ALTER
TABLE
mysql
.
innodb_index_stats
MODIFY
stat_value
BIGINT
UNSIGNED
NOT
NULL
;
FLUSH
TABLE
test_ps_fetch_corrupted
;
SELECT
seq_in_index
,
column_name
,
cardinality
FROM
information_schema
.
statistics
WHERE
table_name
=
'test_ps_fetch_corrupted'
ORDER
BY
index_name
,
seq_in_index
;
SELECT
table_rows
,
avg_row_length
,
max_data_length
,
index_length
FROM
information_schema
.
tables
WHERE
table_name
=
'test_ps_fetch_corrupted'
;
DROP
TABLE
test_ps_fetch_corrupted
;
...
...
storage/innobase/dict/dict0dict.cc
View file @
383f77cd
...
...
@@ -104,11 +104,6 @@ ulong zip_pad_max = 50;
/** Identifies generated InnoDB foreign key names */
static
char
dict_ibfk
[]
=
"_ibfk_"
;
bool
innodb_table_stats_not_found
=
false
;
bool
innodb_index_stats_not_found
=
false
;
static
bool
innodb_table_stats_not_found_reported
=
false
;
static
bool
innodb_index_stats_not_found_reported
=
false
;
/*******************************************************************//**
Tries to find column names for the index and sets the col field of the
index.
...
...
@@ -4600,220 +4595,6 @@ dict_table_check_for_dup_indexes(
}
#endif
/* UNIV_DEBUG */
/** Auxiliary macro used inside dict_table_schema_check(). */
#define CREATE_TYPES_NAMES() \
dtype_sql_name((unsigned) req_schema->columns[i].mtype, \
(unsigned) req_schema->columns[i].prtype_mask, \
(unsigned) req_schema->columns[i].len, \
req_type, sizeof(req_type)); \
dtype_sql_name(table->cols[j].mtype, \
table->cols[j].prtype, \
table->cols[j].len, \
actual_type, sizeof(actual_type))
/*********************************************************************//**
Checks whether a table exists and whether it has the given structure.
The table must have the same number of columns with the same names and
types. The order of the columns does not matter.
The caller must own the dictionary mutex.
dict_table_schema_check() @{
@return DB_SUCCESS if the table exists and contains the necessary columns */
dberr_t
dict_table_schema_check
(
/*====================*/
dict_table_schema_t
*
req_schema
,
/*!< in/out: required table
schema */
char
*
errstr
,
/*!< out: human readable error
message if != DB_SUCCESS is
returned */
size_t
errstr_sz
)
/*!< in: errstr size */
{
char
buf
[
MAX_FULL_NAME_LEN
];
char
req_type
[
64
];
char
actual_type
[
64
];
dict_table_t
*
table
;
ulint
i
;
dict_sys
.
assert_locked
();
table
=
dict_table_get_low
(
req_schema
->
table_name
);
if
(
table
==
NULL
)
{
bool
should_print
=
true
;
/* no such table */
if
(
innobase_strcasecmp
(
req_schema
->
table_name
,
"mysql/innodb_table_stats"
)
==
0
)
{
if
(
innodb_table_stats_not_found_reported
==
false
)
{
innodb_table_stats_not_found
=
true
;
innodb_table_stats_not_found_reported
=
true
;
}
else
{
should_print
=
false
;
}
}
else
if
(
innobase_strcasecmp
(
req_schema
->
table_name
,
"mysql/innodb_index_stats"
)
==
0
)
{
if
(
innodb_index_stats_not_found_reported
==
false
)
{
innodb_index_stats_not_found
=
true
;
innodb_index_stats_not_found_reported
=
true
;
}
else
{
should_print
=
false
;
}
}
if
(
should_print
)
{
snprintf
(
errstr
,
errstr_sz
,
"Table %s not found."
,
ut_format_name
(
req_schema
->
table_name
,
buf
,
sizeof
(
buf
)));
return
(
DB_TABLE_NOT_FOUND
);
}
else
{
return
(
DB_STATS_DO_NOT_EXIST
);
}
}
if
(
!
table
->
is_readable
()
&&
!
table
->
space
)
{
/* missing tablespace */
snprintf
(
errstr
,
errstr_sz
,
"Tablespace for table %s is missing."
,
ut_format_name
(
req_schema
->
table_name
,
buf
,
sizeof
(
buf
)));
return
(
DB_TABLE_NOT_FOUND
);
}
if
(
ulint
(
table
->
n_def
-
DATA_N_SYS_COLS
)
!=
req_schema
->
n_cols
)
{
/* the table has a different number of columns than required */
snprintf
(
errstr
,
errstr_sz
,
"%s has %d columns but should have "
ULINTPF
"."
,
ut_format_name
(
req_schema
->
table_name
,
buf
,
sizeof
buf
),
table
->
n_def
-
DATA_N_SYS_COLS
,
req_schema
->
n_cols
);
return
(
DB_ERROR
);
}
/* For each column from req_schema->columns[] search
whether it is present in table->cols[].
The following algorithm is O(n_cols^2), but is optimized to
be O(n_cols) if the columns are in the same order in both arrays. */
for
(
i
=
0
;
i
<
req_schema
->
n_cols
;
i
++
)
{
ulint
j
=
dict_table_has_column
(
table
,
req_schema
->
columns
[
i
].
name
,
i
);
if
(
j
==
table
->
n_def
)
{
snprintf
(
errstr
,
errstr_sz
,
"required column %s"
" not found in table %s."
,
req_schema
->
columns
[
i
].
name
,
ut_format_name
(
req_schema
->
table_name
,
buf
,
sizeof
(
buf
)));
return
(
DB_ERROR
);
}
/* we found a column with the same name on j'th position,
compare column types and flags */
/* check length for exact match */
if
(
req_schema
->
columns
[
i
].
len
==
table
->
cols
[
j
].
len
)
{
}
else
if
(
!
strcmp
(
req_schema
->
table_name
,
TABLE_STATS_NAME
)
||
!
strcmp
(
req_schema
->
table_name
,
INDEX_STATS_NAME
))
{
ut_ad
(
table
->
cols
[
j
].
len
<
req_schema
->
columns
[
i
].
len
);
ib
::
warn
()
<<
"Table "
<<
req_schema
->
table_name
<<
" has length mismatch in the"
<<
" column name "
<<
req_schema
->
columns
[
i
].
name
<<
". Please run mysql_upgrade"
;
}
else
{
CREATE_TYPES_NAMES
();
snprintf
(
errstr
,
errstr_sz
,
"Column %s in table %s is %s"
" but should be %s (length mismatch)."
,
req_schema
->
columns
[
i
].
name
,
ut_format_name
(
req_schema
->
table_name
,
buf
,
sizeof
(
buf
)),
actual_type
,
req_type
);
return
(
DB_ERROR
);
}
/*
check mtype for exact match.
This check is relaxed to allow use to use TIMESTAMP
(ie INT) for last_update instead of DATA_BINARY.
We have to test for both values as the innodb_table_stats
table may come from MySQL and have the old type.
*/
if
(
req_schema
->
columns
[
i
].
mtype
!=
table
->
cols
[
j
].
mtype
&&
!
(
req_schema
->
columns
[
i
].
mtype
==
DATA_INT
&&
table
->
cols
[
j
].
mtype
==
DATA_FIXBINARY
))
{
CREATE_TYPES_NAMES
();
snprintf
(
errstr
,
errstr_sz
,
"Column %s in table %s is %s"
" but should be %s (type mismatch)."
,
req_schema
->
columns
[
i
].
name
,
ut_format_name
(
req_schema
->
table_name
,
buf
,
sizeof
(
buf
)),
actual_type
,
req_type
);
return
(
DB_ERROR
);
}
/* check whether required prtype mask is set */
if
(
req_schema
->
columns
[
i
].
prtype_mask
!=
0
&&
(
table
->
cols
[
j
].
prtype
&
req_schema
->
columns
[
i
].
prtype_mask
)
!=
req_schema
->
columns
[
i
].
prtype_mask
)
{
CREATE_TYPES_NAMES
();
snprintf
(
errstr
,
errstr_sz
,
"Column %s in table %s is %s"
" but should be %s (flags mismatch)."
,
req_schema
->
columns
[
i
].
name
,
ut_format_name
(
req_schema
->
table_name
,
buf
,
sizeof
(
buf
)),
actual_type
,
req_type
);
return
(
DB_ERROR
);
}
}
if
(
req_schema
->
n_foreign
!=
table
->
foreign_set
.
size
())
{
snprintf
(
errstr
,
errstr_sz
,
"Table %s has "
ULINTPF
" foreign key(s) pointing"
" to other tables, but it must have "
ULINTPF
"."
,
ut_format_name
(
req_schema
->
table_name
,
buf
,
sizeof
(
buf
)),
static_cast
<
ulint
>
(
table
->
foreign_set
.
size
()),
req_schema
->
n_foreign
);
return
(
DB_ERROR
);
}
if
(
req_schema
->
n_referenced
!=
table
->
referenced_set
.
size
())
{
snprintf
(
errstr
,
errstr_sz
,
"There are "
ULINTPF
" foreign key(s) pointing to %s, "
"but there must be "
ULINTPF
"."
,
static_cast
<
ulint
>
(
table
->
referenced_set
.
size
()),
ut_format_name
(
req_schema
->
table_name
,
buf
,
sizeof
(
buf
)),
req_schema
->
n_referenced
);
return
(
DB_ERROR
);
}
return
(
DB_SUCCESS
);
}
/* @} */
/*********************************************************************//**
Converts a database and table name from filesystem encoding
(e.g. d@i1b/a@q1b@1Kc, same format as used in dict_table_t::name) in two
...
...
storage/innobase/dict/dict0stats.cc
View file @
383f77cd
This diff is collapsed.
Click to expand it.
storage/innobase/include/data0type.h
View file @
383f77cd
...
...
@@ -479,19 +479,6 @@ dtype_new_read_for_order_and_null_size(
dtype_t
*
type
,
/*!< in: type struct */
const
byte
*
buf
);
/*!< in: buffer for stored type order info */
/*********************************************************************//**
Returns the type's SQL name (e.g. BIGINT UNSIGNED) from mtype,prtype,len
@return the SQL type name */
UNIV_INLINE
char
*
dtype_sql_name
(
/*===========*/
unsigned
mtype
,
/*!< in: mtype */
unsigned
prtype
,
/*!< in: prtype */
unsigned
len
,
/*!< in: len */
char
*
name
,
/*!< out: SQL name */
unsigned
name_sz
);
/*!< in: size of the name buffer */
/*********************************************************************//**
Validates a data type structure.
@return TRUE if ok */
...
...
storage/innobase/include/data0type.ic
View file @
383f77cd
...
...
@@ -327,103 +327,6 @@ dtype_new_read_for_order_and_null_size(
dtype_set_mblen(type);
}
/*********************************************************************//**
Returns the type's SQL name (e.g. BIGINT UNSIGNED) from mtype,prtype,len
@return the SQL type name */
UNIV_INLINE
char*
dtype_sql_name(
/*===========*/
unsigned mtype, /*!< in: mtype */
unsigned prtype, /*!< in: prtype */
unsigned len, /*!< in: len */
char* name, /*!< out: SQL name */
unsigned name_sz)/*!< in: size of the name buffer */
{
#define APPEND_UNSIGNED() \
do { \
if (prtype & DATA_UNSIGNED) { \
snprintf(name + strlen(name), \
name_sz - strlen(name), \
" UNSIGNED"); \
} \
} while (0)
snprintf(name, name_sz, "UNKNOWN");
switch (mtype) {
case DATA_INT:
switch (len) {
case 1:
snprintf(name, name_sz, "TINYINT");
break;
case 2:
snprintf(name, name_sz, "SMALLINT");
break;
case 3:
snprintf(name, name_sz, "MEDIUMINT");
break;
case 4:
snprintf(name, name_sz, "INT");
break;
case 8:
snprintf(name, name_sz, "BIGINT");
break;
}
APPEND_UNSIGNED();
break;
case DATA_FLOAT:
snprintf(name, name_sz, "FLOAT");
APPEND_UNSIGNED();
break;
case DATA_DOUBLE:
snprintf(name, name_sz, "DOUBLE");
APPEND_UNSIGNED();
break;
case DATA_FIXBINARY:
snprintf(name, name_sz, "BINARY(%u)", len);
break;
case DATA_CHAR:
case DATA_MYSQL:
snprintf(name, name_sz, "CHAR(%u)", len);
break;
case DATA_VARCHAR:
case DATA_VARMYSQL:
snprintf(name, name_sz, "VARCHAR(%u)", len);
break;
case DATA_BINARY:
snprintf(name, name_sz, "VARBINARY(%u)", len);
break;
case DATA_GEOMETRY:
snprintf(name, name_sz, "GEOMETRY");
break;
case DATA_BLOB:
switch (len) {
case 9:
snprintf(name, name_sz, "TINYBLOB");
break;
case 10:
snprintf(name, name_sz, "BLOB");
break;
case 11:
snprintf(name, name_sz, "MEDIUMBLOB");
break;
case 12:
snprintf(name, name_sz, "LONGBLOB");
break;
}
}
if (prtype & DATA_NOT_NULL) {
snprintf(name + strlen(name),
name_sz - strlen(name),
" NOT NULL");
}
return(name);
}
/***********************************************************************//**
Returns the size of a fixed size data type, 0 if not a fixed size type.
@return fixed size, or 0 */
...
...
storage/innobase/include/dict0dict.h
View file @
383f77cd
...
...
@@ -35,8 +35,6 @@ Created 1/8/1996 Heikki Tuuri
#include <deque>
class
MDL_ticket
;
extern
bool
innodb_table_stats_not_found
;
extern
bool
innodb_index_stats_not_found
;
/** the first table or index ID for other than hard-coded system tables */
constexpr
uint8_t
DICT_HDR_FIRST_ID
=
10
;
...
...
@@ -1598,62 +1596,6 @@ extern dict_sys_t dict_sys;
#define dict_sys_lock() dict_sys.lock(SRW_LOCK_CALL)
#define dict_sys_unlock() dict_sys.unlock()
/* Auxiliary structs for checking a table definition @{ */
/* This struct is used to specify the name and type that a column must
have when checking a table's schema. */
struct
dict_col_meta_t
{
const
char
*
name
;
/* column name */
ulint
mtype
;
/* required column main type */
ulint
prtype_mask
;
/* required column precise type mask;
if this is non-zero then all the
bits it has set must also be set
in the column's prtype */
ulint
len
;
/* required column length */
};
/* This struct is used for checking whether a given table exists and
whether it has a predefined schema (number of columns and column names
and types) */
struct
dict_table_schema_t
{
const
char
*
table_name
;
/* the name of the table whose
structure we are checking */
ulint
n_cols
;
/* the number of columns the
table must have */
dict_col_meta_t
*
columns
;
/* metadata for the columns;
this array has n_cols
elements */
ulint
n_foreign
;
/* number of foreign keys this
table has, pointing to other
tables (where this table is
FK child) */
ulint
n_referenced
;
/* number of foreign keys other
tables have, pointing to this
table (where this table is
parent) */
};
/* @} */
/*********************************************************************//**
Checks whether a table exists and whether it has the given structure.
The table must have the same number of columns with the same names and
types. The order of the columns does not matter.
The caller must own the dictionary mutex.
dict_table_schema_check() @{
@return DB_SUCCESS if the table exists and contains the necessary columns */
dberr_t
dict_table_schema_check
(
/*====================*/
dict_table_schema_t
*
req_schema
,
/*!< in/out: required table
schema */
char
*
errstr
,
/*!< out: human readable error
message if != DB_SUCCESS and
!= DB_TABLE_NOT_FOUND is
returned */
size_t
errstr_sz
)
/*!< in: errstr size */
MY_ATTRIBUTE
((
nonnull
,
warn_unused_result
));
/* @} */
/*********************************************************************//**
Converts a database and table name from filesystem encoding
(e.g. d@i1b/a@q1b@1Kc, same format as used in dict_table_t::name) in two
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment