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
Show 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
...
...
@@ -25,6 +25,7 @@ Created Jan 06, 2010 Vasil Dimov
*******************************************************/
#include "dict0stats.h"
#include "dict0priv.h"
#include "ut0ut.h"
#include "ut0rnd.h"
#include "dyn0buf.h"
...
...
@@ -32,6 +33,7 @@ Created Jan 06, 2010 Vasil Dimov
#include "trx0trx.h"
#include "pars0pars.h"
#include <mysql_com.h>
#include "log.h"
#include "btr0btr.h"
#include <algorithm>
...
...
@@ -159,6 +161,307 @@ dict_stats_should_ignore_index(
||
!
index
->
is_committed
());
}
/** expected column definition */
struct
dict_col_meta_t
{
/** column name */
const
char
*
name
;
/** main type */
unsigned
mtype
;
/** prtype mask; all these bits have to be set in prtype */
unsigned
prtype_mask
;
/** column length in bytes */
unsigned
len
;
};
/** For checking whether a table exists and has a predefined schema */
struct
dict_table_schema_t
{
/** table name */
const
char
*
table_name
;
/** table name in SQL */
const
char
*
table_name_sql
;
/** number of columns */
unsigned
n_cols
;
/** columns */
const
dict_col_meta_t
columns
[
8
];
};
static
const
dict_table_schema_t
table_stats_schema
=
{
TABLE_STATS_NAME
,
TABLE_STATS_NAME_PRINT
,
6
,
{
{
"database_name"
,
DATA_VARMYSQL
,
DATA_NOT_NULL
,
192
},
{
"table_name"
,
DATA_VARMYSQL
,
DATA_NOT_NULL
,
597
},
{
"last_update"
,
DATA_INT
,
DATA_NOT_NULL
|
DATA_UNSIGNED
,
4
},
{
"n_rows"
,
DATA_INT
,
DATA_NOT_NULL
|
DATA_UNSIGNED
,
8
},
{
"clustered_index_size"
,
DATA_INT
,
DATA_NOT_NULL
|
DATA_UNSIGNED
,
8
},
{
"sum_of_other_index_sizes"
,
DATA_INT
,
DATA_NOT_NULL
|
DATA_UNSIGNED
,
8
},
}
};
static
const
dict_table_schema_t
index_stats_schema
=
{
INDEX_STATS_NAME
,
INDEX_STATS_NAME_PRINT
,
8
,
{
{
"database_name"
,
DATA_VARMYSQL
,
DATA_NOT_NULL
,
192
},
{
"table_name"
,
DATA_VARMYSQL
,
DATA_NOT_NULL
,
597
},
{
"index_name"
,
DATA_VARMYSQL
,
DATA_NOT_NULL
,
192
},
{
"last_update"
,
DATA_INT
,
DATA_NOT_NULL
|
DATA_UNSIGNED
,
4
},
{
"stat_name"
,
DATA_VARMYSQL
,
DATA_NOT_NULL
,
64
*
3
},
{
"stat_value"
,
DATA_INT
,
DATA_NOT_NULL
|
DATA_UNSIGNED
,
8
},
{
"sample_size"
,
DATA_INT
,
DATA_UNSIGNED
,
8
},
{
"stat_description"
,
DATA_VARMYSQL
,
DATA_NOT_NULL
,
1024
*
3
}
}
};
/** Construct the type's SQL name (e.g. BIGINT UNSIGNED)
@param mtype InnoDB main type
@param prtype InnoDB precise type
@param len length of the column
@param name the SQL name
@param name_sz size of the name buffer
@return number of bytes written (excluding the terminating NUL byte) */
static
int
dtype_sql_name
(
unsigned
mtype
,
unsigned
prtype
,
unsigned
len
,
char
*
name
,
size_t
name_sz
)
{
const
char
*
Unsigned
=
""
;
const
char
*
Main
=
"UNKNOWN"
;
switch
(
mtype
)
{
case
DATA_INT
:
switch
(
len
)
{
case
1
:
Main
=
"TINYINT"
;
break
;
case
2
:
Main
=
"SMALLINT"
;
break
;
case
3
:
Main
=
"MEDIUMINT"
;
break
;
case
4
:
Main
=
"INT"
;
break
;
case
8
:
Main
=
"BIGINT"
;
break
;
}
append_unsigned:
if
(
prtype
&
DATA_UNSIGNED
)
Unsigned
=
" UNSIGNED"
;
len
=
0
;
break
;
case
DATA_FLOAT
:
Main
=
"FLOAT"
;
goto
append_unsigned
;
case
DATA_DOUBLE
:
Main
=
"DOUBLE"
;
goto
append_unsigned
;
case
DATA_FIXBINARY
:
Main
=
"BINARY"
;
break
;
case
DATA_CHAR
:
case
DATA_MYSQL
:
Main
=
"CHAR"
;
break
;
case
DATA_VARCHAR
:
case
DATA_VARMYSQL
:
Main
=
"VARCHAR"
;
break
;
case
DATA_BINARY
:
Main
=
"VARBINARY"
;
break
;
case
DATA_GEOMETRY
:
Main
=
"GEOMETRY"
;
len
=
0
;
break
;
case
DATA_BLOB
:
switch
(
len
)
{
case
9
:
Main
=
"TINYBLOB"
;
break
;
case
10
:
Main
=
"BLOB"
;
break
;
case
11
:
Main
=
"MEDIUMBLOB"
;
break
;
case
12
:
Main
=
"LONGBLOB"
;
break
;
}
len
=
0
;
}
const
char
*
Not_null
=
(
prtype
&
DATA_NOT_NULL
)
?
" NOT NULL"
:
""
;
if
(
len
)
return
snprintf
(
name
,
name_sz
,
"%s(%u)%s%s"
,
Main
,
len
,
Unsigned
,
Not_null
);
else
return
snprintf
(
name
,
name_sz
,
"%s%s%s"
,
Main
,
Unsigned
,
Not_null
);
}
static
bool
innodb_table_stats_not_found
;
static
bool
innodb_index_stats_not_found
;
static
bool
innodb_table_stats_not_found_reported
;
static
bool
innodb_index_stats_not_found_reported
;
/*********************************************************************//**
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 */
static
dberr_t
dict_table_schema_check
(
/*====================*/
const
dict_table_schema_t
*
req_schema
,
/*!< in: required table
schema */
char
*
errstr
,
/*!< out: human readable error
message if != DB_SUCCESS is
returned */
size_t
errstr_sz
)
/*!< in: errstr size */
{
const
dict_table_t
*
table
=
dict_table_get_low
(
req_schema
->
table_name
);
if
(
!
table
)
{
if
(
req_schema
==
&
table_stats_schema
)
{
if
(
innodb_table_stats_not_found_reported
)
{
return
DB_STATS_DO_NOT_EXIST
;
}
innodb_table_stats_not_found
=
true
;
innodb_table_stats_not_found_reported
=
true
;
}
else
{
ut_ad
(
req_schema
==
&
index_stats_schema
);
if
(
innodb_index_stats_not_found_reported
)
{
return
DB_STATS_DO_NOT_EXIST
;
}
innodb_index_stats_not_found
=
true
;
innodb_index_stats_not_found_reported
=
true
;
}
snprintf
(
errstr
,
errstr_sz
,
"Table %s not found."
,
req_schema
->
table_name_sql
);
return
DB_TABLE_NOT_FOUND
;
}
if
(
!
table
->
is_readable
()
&&
!
table
->
space
)
{
/* missing tablespace */
snprintf
(
errstr
,
errstr_sz
,
"Tablespace for table %s is missing."
,
req_schema
->
table_name_sql
);
return
DB_TABLE_NOT_FOUND
;
}
if
(
unsigned
(
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 %u."
,
req_schema
->
table_name_sql
,
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
(
unsigned
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
,
req_schema
->
table_name_sql
);
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
)
{
ut_ad
(
table
->
cols
[
j
].
len
<
req_schema
->
columns
[
i
].
len
);
sql_print_warning
(
"InnoDB: Table %s has"
" length mismatch in the"
" column name %s."
" Please run mariadb-upgrade"
,
req_schema
->
table_name_sql
,
req_schema
->
columns
[
i
].
name
);
}
/*
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
))
{
}
else
if
((
~
table
->
cols
[
j
].
prtype
&
req_schema
->
columns
[
i
].
prtype_mask
))
{
}
else
{
continue
;
}
int
s
=
snprintf
(
errstr
,
errstr_sz
,
"Column %s in table %s is "
,
req_schema
->
columns
[
i
].
name
,
req_schema
->
table_name_sql
);
if
(
s
<
0
||
static_cast
<
size_t
>
(
s
)
>=
errstr_sz
)
{
return
DB_ERROR
;
}
errstr
+=
s
;
errstr_sz
-=
s
;
s
=
dtype_sql_name
(
table
->
cols
[
j
].
mtype
,
table
->
cols
[
j
].
prtype
,
table
->
cols
[
j
].
len
,
errstr
,
errstr_sz
);
if
(
s
<
0
||
static_cast
<
size_t
>
(
s
)
+
sizeof
" but should be "
>=
errstr_sz
)
{
return
DB_ERROR
;
}
errstr
+=
s
;
memcpy
(
errstr
,
" but should be "
,
sizeof
" but should be "
);
errstr
+=
(
sizeof
" but should be "
)
-
1
;
errstr_sz
-=
s
+
(
sizeof
" but should be "
)
-
1
;
s
=
dtype_sql_name
(
req_schema
->
columns
[
i
].
mtype
,
req_schema
->
columns
[
i
].
prtype_mask
,
req_schema
->
columns
[
i
].
len
,
errstr
,
errstr_sz
);
return
DB_ERROR
;
}
if
(
size_t
n_foreign
=
table
->
foreign_set
.
size
())
{
snprintf
(
errstr
,
errstr_sz
,
"Table %s has %zu foreign key(s) pointing"
" to other tables, but it must have 0."
,
req_schema
->
table_name_sql
,
n_foreign
);
return
DB_ERROR
;
}
if
(
size_t
n_referenced
=
table
->
referenced_set
.
size
())
{
snprintf
(
errstr
,
errstr_sz
,
"There are %zu foreign key(s) pointing to %s, "
"but there must be 0."
,
n_referenced
,
req_schema
->
table_name_sql
);
return
DB_ERROR
;
}
return
DB_SUCCESS
;
}
/*********************************************************************//**
Checks whether the persistent statistics storage exists and that all
tables have the proper structure.
...
...
@@ -170,68 +473,6 @@ dict_stats_persistent_storage_check(
bool
caller_has_dict_sys_mutex
)
/*!< in: true if the caller
owns dict_sys.mutex */
{
/* definition for the table TABLE_STATS_NAME */
dict_col_meta_t
table_stats_columns
[]
=
{
{
"database_name"
,
DATA_VARMYSQL
,
DATA_NOT_NULL
,
192
},
{
"table_name"
,
DATA_VARMYSQL
,
DATA_NOT_NULL
,
597
},
{
"last_update"
,
DATA_INT
,
DATA_NOT_NULL
|
DATA_UNSIGNED
,
4
},
{
"n_rows"
,
DATA_INT
,
DATA_NOT_NULL
|
DATA_UNSIGNED
,
8
},
{
"clustered_index_size"
,
DATA_INT
,
DATA_NOT_NULL
|
DATA_UNSIGNED
,
8
},
{
"sum_of_other_index_sizes"
,
DATA_INT
,
DATA_NOT_NULL
|
DATA_UNSIGNED
,
8
}
};
dict_table_schema_t
table_stats_schema
=
{
TABLE_STATS_NAME
,
UT_ARR_SIZE
(
table_stats_columns
),
table_stats_columns
,
0
/* n_foreign */
,
0
/* n_referenced */
};
/* definition for the table INDEX_STATS_NAME */
dict_col_meta_t
index_stats_columns
[]
=
{
{
"database_name"
,
DATA_VARMYSQL
,
DATA_NOT_NULL
,
192
},
{
"table_name"
,
DATA_VARMYSQL
,
DATA_NOT_NULL
,
597
},
{
"index_name"
,
DATA_VARMYSQL
,
DATA_NOT_NULL
,
192
},
{
"last_update"
,
DATA_INT
,
DATA_NOT_NULL
|
DATA_UNSIGNED
,
4
},
{
"stat_name"
,
DATA_VARMYSQL
,
DATA_NOT_NULL
,
64
*
3
},
{
"stat_value"
,
DATA_INT
,
DATA_NOT_NULL
|
DATA_UNSIGNED
,
8
},
{
"sample_size"
,
DATA_INT
,
DATA_UNSIGNED
,
8
},
{
"stat_description"
,
DATA_VARMYSQL
,
DATA_NOT_NULL
,
1024
*
3
}
};
dict_table_schema_t
index_stats_schema
=
{
INDEX_STATS_NAME
,
UT_ARR_SIZE
(
index_stats_columns
),
index_stats_columns
,
0
/* n_foreign */
,
0
/* n_referenced */
};
char
errstr
[
512
];
dberr_t
ret
;
...
...
@@ -3925,129 +4166,6 @@ dict_stats_rename_index(
/* tests @{ */
#ifdef UNIV_ENABLE_UNIT_TEST_DICT_STATS
/* The following unit tests test some of the functions in this file
individually, such testing cannot be performed by the mysql-test framework
via SQL. */
/* test_dict_table_schema_check() @{ */
void
test_dict_table_schema_check
()
{
/*
CREATE TABLE tcheck (
c01 VARCHAR(123),
c02 INT,
c03 INT NOT NULL,
c04 INT UNSIGNED,
c05 BIGINT,
c06 BIGINT UNSIGNED NOT NULL,
c07 TIMESTAMP
) ENGINE=INNODB;
*/
/* definition for the table 'test/tcheck' */
dict_col_meta_t
columns
[]
=
{
{
"c01"
,
DATA_VARCHAR
,
0
,
123
},
{
"c02"
,
DATA_INT
,
0
,
4
},
{
"c03"
,
DATA_INT
,
DATA_NOT_NULL
,
4
},
{
"c04"
,
DATA_INT
,
DATA_UNSIGNED
,
4
},
{
"c05"
,
DATA_INT
,
0
,
8
},
{
"c06"
,
DATA_INT
,
DATA_NOT_NULL
|
DATA_UNSIGNED
,
8
},
{
"c07"
,
DATA_INT
,
0
,
4
},
{
"c_extra"
,
DATA_INT
,
0
,
4
}
};
dict_table_schema_t
schema
=
{
"test/tcheck"
,
0
/* will be set individually for each test below */
,
columns
};
char
errstr
[
512
];
snprintf
(
errstr
,
sizeof
(
errstr
),
"Table not found"
);
/* prevent any data dictionary modifications while we are checking
the tables' structure */
dict_sys
.
mutex_lock
();
/* check that a valid table is reported as valid */
schema
.
n_cols
=
7
;
if
(
dict_table_schema_check
(
&
schema
,
errstr
,
sizeof
(
errstr
))
==
DB_SUCCESS
)
{
printf
(
"OK: test.tcheck ok
\n
"
);
}
else
{
printf
(
"ERROR: %s
\n
"
,
errstr
);
printf
(
"ERROR: test.tcheck not present or corrupted
\n
"
);
goto
test_dict_table_schema_check_end
;
}
/* check columns with wrong length */
schema
.
columns
[
1
].
len
=
8
;
if
(
dict_table_schema_check
(
&
schema
,
errstr
,
sizeof
(
errstr
))
!=
DB_SUCCESS
)
{
printf
(
"OK: test.tcheck.c02 has different length and is"
" reported as corrupted
\n
"
);
}
else
{
printf
(
"OK: test.tcheck.c02 has different length but is"
" reported as ok
\n
"
);
goto
test_dict_table_schema_check_end
;
}
schema
.
columns
[
1
].
len
=
4
;
/* request that c02 is NOT NULL while actually it does not have
this flag set */
schema
.
columns
[
1
].
prtype_mask
|=
DATA_NOT_NULL
;
if
(
dict_table_schema_check
(
&
schema
,
errstr
,
sizeof
(
errstr
))
!=
DB_SUCCESS
)
{
printf
(
"OK: test.tcheck.c02 does not have NOT NULL while"
" it should and is reported as corrupted
\n
"
);
}
else
{
printf
(
"ERROR: test.tcheck.c02 does not have NOT NULL while"
" it should and is not reported as corrupted
\n
"
);
goto
test_dict_table_schema_check_end
;
}
schema
.
columns
[
1
].
prtype_mask
&=
~
DATA_NOT_NULL
;
/* check a table that contains some extra columns */
schema
.
n_cols
=
6
;
if
(
dict_table_schema_check
(
&
schema
,
errstr
,
sizeof
(
errstr
))
==
DB_SUCCESS
)
{
printf
(
"ERROR: test.tcheck has more columns but is not"
" reported as corrupted
\n
"
);
goto
test_dict_table_schema_check_end
;
}
else
{
printf
(
"OK: test.tcheck has more columns and is"
" reported as corrupted
\n
"
);
}
/* check a table that has some columns missing */
schema
.
n_cols
=
8
;
if
(
dict_table_schema_check
(
&
schema
,
errstr
,
sizeof
(
errstr
))
!=
DB_SUCCESS
)
{
printf
(
"OK: test.tcheck has missing columns and is"
" reported as corrupted
\n
"
);
}
else
{
printf
(
"ERROR: test.tcheck has missing columns but is"
" reported as ok
\n
"
);
goto
test_dict_table_schema_check_end
;
}
/* check non-existent table */
schema
.
table_name
=
"test/tcheck_nonexistent"
;
if
(
dict_table_schema_check
(
&
schema
,
errstr
,
sizeof
(
errstr
))
!=
DB_SUCCESS
)
{
printf
(
"OK: test.tcheck_nonexistent is not present
\n
"
);
}
else
{
printf
(
"ERROR: test.tcheck_nonexistent is present!?
\n
"
);
goto
test_dict_table_schema_check_end
;
}
test_dict_table_schema_check_end:
dict_sys
.
mutex_unlock
();
}
/* @} */
/* save/fetch aux macros @{ */
#define TEST_DATABASE_NAME "foobardb"
#define TEST_TABLE_NAME "test_dict_stats"
...
...
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