summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/sp-destruct.result34
-rw-r--r--mysql-test/t/sp-destruct.test54
-rw-r--r--sql/event_db_repository.cc27
-rw-r--r--sql/sp.cc194
-rw-r--r--sql/sql_acl.cc7
-rw-r--r--sql/sql_acl.h3
-rw-r--r--sql/table.cc98
-rw-r--r--sql/table.h53
8 files changed, 381 insertions, 89 deletions
diff --git a/mysql-test/r/sp-destruct.result b/mysql-test/r/sp-destruct.result
index d7d44061b76..b6891df2420 100644
--- a/mysql-test/r/sp-destruct.result
+++ b/mysql-test/r/sp-destruct.result
@@ -1,3 +1,4 @@
+call mtr.add_suppression("Column count of mysql.proc is wrong. Expected 20, found 19. The table is probably corrupted");
use test;
drop procedure if exists bug14233;
drop function if exists bug14233;
@@ -11,11 +12,13 @@ create table t1 (id int);
create trigger t1_ai after insert on t1 for each row call bug14233();
alter table mysql.proc drop type;
call bug14233();
-ERROR HY000: Failed to load routine test.bug14233. The table mysql.proc is missing, corrupt, or contains bad data (internal code -5)
+ERROR HY000: Column count of mysql.proc is wrong. Expected 20, found 19. The table is probably corrupted
create view v1 as select bug14233_f();
-ERROR HY000: Failed to load routine test.bug14233_f. The table mysql.proc is missing, corrupt, or contains bad data (internal code -5)
+ERROR HY000: Column count of mysql.proc is wrong. Expected 20, found 19. The table is probably corrupted
insert into t1 values (0);
-ERROR HY000: Failed to load routine test.bug14233. The table mysql.proc is missing, corrupt, or contains bad data (internal code -5)
+ERROR HY000: Column count of mysql.proc is wrong. Expected 20, found 19. The table is probably corrupted
+show procedure status;
+ERROR HY000: Column count of mysql.proc is wrong. Expected 20, found 19. The table is probably corrupted
flush table mysql.proc;
call bug14233();
ERROR HY000: Incorrect information in file: './mysql/proc.frm'
@@ -88,3 +91,28 @@ show procedure status where db=DATABASE();
Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation
show function status where db=DATABASE();
Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation
+DROP TABLE IF EXISTS proc_backup;
+DROP PROCEDURE IF EXISTS p1;
+# Backup the proc table
+RENAME TABLE mysql.proc TO proc_backup;
+CREATE TABLE mysql.proc LIKE proc_backup;
+FLUSH TABLE mysql.proc;
+# Test with a valid table.
+CREATE PROCEDURE p1()
+SET @foo = 10;
+CALL p1();
+SHOW PROCEDURE STATUS;
+Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation
+test p1 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER latin1 latin1_swedish_ci latin1_swedish_ci
+# Modify a field of the table.
+ALTER TABLE mysql.proc MODIFY comment CHAR (32);
+CREATE PROCEDURE p2()
+SET @foo = 10;
+ERROR HY000: Cannot load from mysql.proc. The table is probably corrupted
+# Procedure loaded from the cache
+CALL p1();
+SHOW PROCEDURE STATUS;
+ERROR HY000: Cannot load from mysql.proc. The table is probably corrupted
+DROP TABLE mysql.proc;
+RENAME TABLE proc_backup TO mysql.proc;
+FLUSH TABLE mysql.proc;
diff --git a/mysql-test/t/sp-destruct.test b/mysql-test/t/sp-destruct.test
index 14c38a2fdb4..720c24b2c24 100644
--- a/mysql-test/t/sp-destruct.test
+++ b/mysql-test/t/sp-destruct.test
@@ -12,6 +12,9 @@
# mysqltest should be fixed to allow REPLACE_RESULT in error message
-- source include/not_embedded.inc
+# Supress warnings written to the log file
+call mtr.add_suppression("Column count of mysql.proc is wrong. Expected 20, found 19. The table is probably corrupted");
+
# Backup proc table
let $MYSQLD_DATADIR= `select @@datadir`;
--copy_file $MYSQLD_DATADIR/mysql/proc.frm $MYSQLTEST_VARDIR/tmp/proc.frm
@@ -38,15 +41,14 @@ create trigger t1_ai after insert on t1 for each row call bug14233();
# Unsupported tampering with the mysql.proc definition
alter table mysql.proc drop type;
---replace_result $MYSQL_TEST_DIR .
---error ER_SP_PROC_TABLE_CORRUPT
+--error ER_COL_COUNT_DOESNT_MATCH_CORRUPTED
call bug14233();
---replace_result $MYSQL_TEST_DIR .
---error ER_SP_PROC_TABLE_CORRUPT
+--error ER_COL_COUNT_DOESNT_MATCH_CORRUPTED
create view v1 as select bug14233_f();
---replace_result $MYSQL_TEST_DIR .
---error ER_SP_PROC_TABLE_CORRUPT
+--error ER_COL_COUNT_DOESNT_MATCH_CORRUPTED
insert into t1 values (0);
+--error ER_COL_COUNT_DOESNT_MATCH_CORRUPTED
+show procedure status;
flush table mysql.proc;
@@ -155,3 +157,43 @@ drop procedure bug14233_3;
# Assert: These should show nothing.
show procedure status where db=DATABASE();
show function status where db=DATABASE();
+
+#
+# Bug#41726 upgrade from 5.0 to 5.1.30 crashes if you didn't run mysql_upgrade
+#
+
+
+--disable_warnings
+DROP TABLE IF EXISTS proc_backup;
+DROP PROCEDURE IF EXISTS p1;
+--enable_warnings
+
+--echo # Backup the proc table
+
+RENAME TABLE mysql.proc TO proc_backup;
+CREATE TABLE mysql.proc LIKE proc_backup;
+FLUSH TABLE mysql.proc;
+
+--echo # Test with a valid table.
+
+CREATE PROCEDURE p1()
+ SET @foo = 10;
+CALL p1();
+--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+SHOW PROCEDURE STATUS;
+
+--echo # Modify a field of the table.
+
+ALTER TABLE mysql.proc MODIFY comment CHAR (32);
+
+--error ER_CANNOT_LOAD_FROM_TABLE
+CREATE PROCEDURE p2()
+ SET @foo = 10;
+--echo # Procedure loaded from the cache
+CALL p1();
+--error ER_CANNOT_LOAD_FROM_TABLE
+SHOW PROCEDURE STATUS;
+
+DROP TABLE mysql.proc;
+RENAME TABLE proc_backup TO mysql.proc;
+FLUSH TABLE mysql.proc;
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index 8faab5023da..9f3863eb2b0 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -26,7 +26,7 @@
*/
static
-const TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] =
+const TABLE_FIELD_TYPE event_table_fields[ET_FIELD_COUNT] =
{
{
{ C_STRING_WITH_LEN("db") },
@@ -151,6 +151,24 @@ const TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] =
}
};
+static const TABLE_FIELD_DEF
+ event_table_def= {ET_FIELD_COUNT, event_table_fields};
+
+class Event_db_intact : public Table_check_intact
+{
+protected:
+ void report_error(uint, const char *fmt, ...)
+ {
+ va_list args;
+ va_start(args, fmt);
+ error_log_print(ERROR_LEVEL, fmt, args);
+ va_end(args);
+ }
+};
+
+/** In case of an error, a message is printed to the error log. */
+static Event_db_intact table_intact;
+
/**
Puts some data common to CREATE and ALTER EVENT into a row.
@@ -1117,10 +1135,8 @@ Event_db_repository::check_system_tables(THD *thd)
}
else
{
- if (table_check_intact(tables.table, MYSQL_DB_FIELD_COUNT,
- mysql_db_table_fields))
+ if (table_intact.check(tables.table, &mysql_db_table_def))
ret= 1;
- /* in case of an error, the message is printed inside table_check_intact */
close_thread_tables(thd);
}
@@ -1154,9 +1170,8 @@ Event_db_repository::check_system_tables(THD *thd)
}
else
{
- if (table_check_intact(tables.table, ET_FIELD_COUNT, event_table_fields))
+ if (table_intact.check(tables.table, &event_table_def))
ret= 1;
- /* in case of an error, the message is printed inside table_check_intact */
close_thread_tables(thd);
}
diff --git a/sql/sp.cc b/sql/sp.cc
index b254ba8e694..d3c5dfb96d0 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -70,6 +70,122 @@ enum
MYSQL_PROC_FIELD_COUNT
};
+static const
+TABLE_FIELD_TYPE proc_table_fields[MYSQL_PROC_FIELD_COUNT] =
+{
+ {
+ { C_STRING_WITH_LEN("db") },
+ { C_STRING_WITH_LEN("char(64)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("name") },
+ { C_STRING_WITH_LEN("char(64)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("type") },
+ { C_STRING_WITH_LEN("enum('FUNCTION','PROCEDURE')") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("specific_name") },
+ { C_STRING_WITH_LEN("char(64)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("language") },
+ { C_STRING_WITH_LEN("enum('SQL')") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("sql_data_access") },
+ { C_STRING_WITH_LEN("enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA')") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("is_deterministic") },
+ { C_STRING_WITH_LEN("enum('YES','NO')") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("security_type") },
+ { C_STRING_WITH_LEN("enum('INVOKER','DEFINER')") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("param_list") },
+ { C_STRING_WITH_LEN("blob") },
+ { NULL, 0 }
+ },
+
+ {
+ { C_STRING_WITH_LEN("returns") },
+ { C_STRING_WITH_LEN("longblob") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("body") },
+ { C_STRING_WITH_LEN("longblob") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("definer") },
+ { C_STRING_WITH_LEN("char(77)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("created") },
+ { C_STRING_WITH_LEN("timestamp") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("modified") },
+ { C_STRING_WITH_LEN("timestamp") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("sql_mode") },
+ { C_STRING_WITH_LEN("set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES',"
+ "'IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION',"
+ "'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB',"
+ "'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40',"
+ "'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES',"
+ "'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES',"
+ "'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER',"
+ "'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH')") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("comment") },
+ { C_STRING_WITH_LEN("char(64)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("character_set_client") },
+ { C_STRING_WITH_LEN("char(32)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("collation_connection") },
+ { C_STRING_WITH_LEN("char(32)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("db_collation") },
+ { C_STRING_WITH_LEN("char(32)") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("body_utf8") },
+ { C_STRING_WITH_LEN("longblob") },
+ { NULL, 0 }
+ }
+};
+
+static const TABLE_FIELD_DEF
+ proc_table_def= {MYSQL_PROC_FIELD_COUNT, proc_table_fields};
+
/*************************************************************************/
/**
@@ -247,6 +363,50 @@ Stored_routine_creation_ctx::load_from_db(THD *thd,
/*************************************************************************/
+class Proc_table_intact : public Table_check_intact
+{
+private:
+ bool m_print_once;
+
+public:
+ Proc_table_intact() : m_print_once(TRUE) {}
+
+protected:
+ void report_error(uint code, const char *fmt, ...);
+};
+
+
+/**
+ Report failure to validate the mysql.proc table definition.
+ Print a message to the error log only once.
+*/
+
+void Proc_table_intact::report_error(uint code, const char *fmt, ...)
+{
+ va_list args;
+ char buf[512];
+
+ va_start(args, fmt);
+ my_vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ if (code)
+ my_message(code, buf, MYF(0));
+ else
+ my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "proc");
+
+ if (m_print_once)
+ {
+ m_print_once= FALSE;
+ sql_print_error("%s", buf);
+ }
+};
+
+
+/** Single instance used to control printing to the error log. */
+static Proc_table_intact proc_table_intact;
+
+
/**
Open the mysql.proc table for read.
@@ -266,15 +426,17 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
DBUG_ENTER("open_proc_table_for_read");
TABLE_LIST table;
- bzero((char*) &table, sizeof(table));
- table.db= (char*) "mysql";
- table.table_name= table.alias= (char*)"proc";
- table.lock_type= TL_READ;
+ table.init_one_table("mysql", "proc", TL_READ);
+
+ if (open_system_tables_for_read(thd, &table, backup))
+ DBUG_RETURN(NULL);
- if (!open_system_tables_for_read(thd, &table, backup))
+ if (!proc_table_intact.check(table.table, &proc_table_def))
DBUG_RETURN(table.table);
- else
- DBUG_RETURN(0);
+
+ close_system_tables(thd, backup);
+
+ DBUG_RETURN(NULL);
}
@@ -296,13 +458,19 @@ static TABLE *open_proc_table_for_update(THD *thd)
{
DBUG_ENTER("open_proc_table_for_update");
- TABLE_LIST table;
- bzero((char*) &table, sizeof(table));
- table.db= (char*) "mysql";
- table.table_name= table.alias= (char*)"proc";
- table.lock_type= TL_WRITE;
+ TABLE *table;
+ TABLE_LIST table_list;
+ table_list.init_one_table("mysql", "proc", TL_WRITE);
+
+ if (!(table= open_system_table_for_update(thd, &table_list)))
+ DBUG_RETURN(NULL);
+
+ if (!proc_table_intact.check(table, &proc_table_def))
+ DBUG_RETURN(table);
+
+ close_thread_tables(thd);
- DBUG_RETURN(open_system_table_for_update(thd, &table));
+ DBUG_RETURN(NULL);
}
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index fd87a5c0961..eb91f66d114 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -31,9 +31,8 @@
#include "sp_head.h"
#include "sp.h"
-time_t mysql_db_table_last_check= 0L;
-
-TABLE_FIELD_W_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = {
+static const
+TABLE_FIELD_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = {
{
{ C_STRING_WITH_LEN("Host") },
{ C_STRING_WITH_LEN("char(60)") },
@@ -146,6 +145,8 @@ TABLE_FIELD_W_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = {
}
};
+const TABLE_FIELD_DEF
+ mysql_db_table_def= {MYSQL_DB_FIELD_COUNT, mysql_db_table_fields};
#ifndef NO_EMBEDDED_ACCESS_CHECKS
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index a8090fba2e7..4c835e2718c 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -159,8 +159,7 @@ enum mysql_db_table_field
MYSQL_DB_FIELD_COUNT
};
-extern TABLE_FIELD_W_TYPE mysql_db_table_fields[];
-extern time_t mysql_db_table_last_check;
+extern const TABLE_FIELD_DEF mysql_db_table_def;
/* Classes */
diff --git a/sql/table.cc b/sql/table.cc
index 35e8d83369f..752b6ba0bd4 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -2811,34 +2811,38 @@ bool check_column_name(const char *name)
and such errors never reach the user.
*/
-my_bool
-table_check_intact(TABLE *table, const uint table_f_count,
- const TABLE_FIELD_W_TYPE *table_def)
+bool
+Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def)
{
uint i;
my_bool error= FALSE;
- my_bool fields_diff_count;
+ const TABLE_FIELD_TYPE *field_def= table_def->field;
DBUG_ENTER("table_check_intact");
DBUG_PRINT("info",("table: %s expected_count: %d",
- table->alias, table_f_count));
+ table->alias, table_def->count));
- fields_diff_count= (table->s->fields != table_f_count);
- if (fields_diff_count)
+ /* Whether the table definition has already been validated. */
+ if (table->s->table_field_def_cache == table_def)
+ DBUG_RETURN(FALSE);
+
+ if (table->s->fields != table_def->count)
{
DBUG_PRINT("info", ("Column count has changed, checking the definition"));
/* previous MySQL version */
if (MYSQL_VERSION_ID > table->s->mysql_version)
{
- sql_print_error(ER(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE),
- table->alias, table_f_count, table->s->fields,
- table->s->mysql_version, MYSQL_VERSION_ID);
+ report_error(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE,
+ ER(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE),
+ table->alias, table_def->count, table->s->fields,
+ table->s->mysql_version, MYSQL_VERSION_ID);
DBUG_RETURN(TRUE);
}
else if (MYSQL_VERSION_ID == table->s->mysql_version)
{
- sql_print_error(ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED), table->alias,
- table_f_count, table->s->fields);
+ report_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED,
+ ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED), table->alias,
+ table_def->count, table->s->fields);
DBUG_RETURN(TRUE);
}
/*
@@ -2850,7 +2854,7 @@ table_check_intact(TABLE *table, const uint table_f_count,
*/
}
char buffer[STRING_BUFFER_USUAL_SIZE];
- for (i=0 ; i < table_f_count; i++, table_def++)
+ for (i=0 ; i < table_def->count; i++, field_def++)
{
String sql_type(buffer, sizeof(buffer), system_charset_info);
sql_type.length(0);
@@ -2858,18 +2862,18 @@ table_check_intact(TABLE *table, const uint table_f_count,
{
Field *field= table->field[i];
- if (strncmp(field->field_name, table_def->name.str,
- table_def->name.length))
+ if (strncmp(field->field_name, field_def->name.str,
+ field_def->name.length))
{
/*
Name changes are not fatal, we use ordinal numbers to access columns.
Still this can be a sign of a tampered table, output an error
to the error log.
*/
- sql_print_error("Incorrect definition of table %s.%s: "
- "expected column '%s' at position %d, found '%s'.",
- table->s->db.str, table->alias, table_def->name.str, i,
- field->field_name);
+ report_error(0, "Incorrect definition of table %s.%s: "
+ "expected column '%s' at position %d, found '%s'.",
+ table->s->db.str, table->alias, field_def->name.str, i,
+ field->field_name);
}
field->sql_type(sql_type);
/*
@@ -2889,47 +2893,51 @@ table_check_intact(TABLE *table, const uint table_f_count,
the new table definition is backward compatible with the
original one.
*/
- if (strncmp(sql_type.c_ptr_safe(), table_def->type.str,
- table_def->type.length - 1))
+ if (strncmp(sql_type.c_ptr_safe(), field_def->type.str,
+ field_def->type.length - 1))
{
- sql_print_error("Incorrect definition of table %s.%s: "
- "expected column '%s' at position %d to have type "
- "%s, found type %s.", table->s->db.str, table->alias,
- table_def->name.str, i, table_def->type.str,
- sql_type.c_ptr_safe());
+ report_error(0, "Incorrect definition of table %s.%s: "
+ "expected column '%s' at position %d to have type "
+ "%s, found type %s.", table->s->db.str, table->alias,
+ field_def->name.str, i, field_def->type.str,
+ sql_type.c_ptr_safe());
error= TRUE;
}
- else if (table_def->cset.str && !field->has_charset())
+ else if (field_def->cset.str && !field->has_charset())
{
- sql_print_error("Incorrect definition of table %s.%s: "
- "expected the type of column '%s' at position %d "
- "to have character set '%s' but the type has no "
- "character set.", table->s->db.str, table->alias,
- table_def->name.str, i, table_def->cset.str);
+ report_error(0, "Incorrect definition of table %s.%s: "
+ "expected the type of column '%s' at position %d "
+ "to have character set '%s' but the type has no "
+ "character set.", table->s->db.str, table->alias,
+ field_def->name.str, i, field_def->cset.str);
error= TRUE;
}
- else if (table_def->cset.str &&
- strcmp(field->charset()->csname, table_def->cset.str))
+ else if (field_def->cset.str &&
+ strcmp(field->charset()->csname, field_def->cset.str))
{
- sql_print_error("Incorrect definition of table %s.%s: "
- "expected the type of column '%s' at position %d "
- "to have character set '%s' but found "
- "character set '%s'.", table->s->db.str, table->alias,
- table_def->name.str, i, table_def->cset.str,
- field->charset()->csname);
+ report_error(0, "Incorrect definition of table %s.%s: "
+ "expected the type of column '%s' at position %d "
+ "to have character set '%s' but found "
+ "character set '%s'.", table->s->db.str, table->alias,
+ field_def->name.str, i, field_def->cset.str,
+ field->charset()->csname);
error= TRUE;
}
}
else
{
- sql_print_error("Incorrect definition of table %s.%s: "
- "expected column '%s' at position %d to have type %s "
- " but the column is not found.",
- table->s->db.str, table->alias,
- table_def->name.str, i, table_def->type.str);
+ report_error(0, "Incorrect definition of table %s.%s: "
+ "expected column '%s' at position %d to have type %s "
+ " but the column is not found.",
+ table->s->db.str, table->alias,
+ field_def->name.str, i, field_def->type.str);
error= TRUE;
}
}
+
+ if (! error)
+ table->s->table_field_def_cache= table_def;
+
DBUG_RETURN(error);
}
diff --git a/sql/table.h b/sql/table.h
index e4a382c799f..eae261cc97d 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -285,6 +285,36 @@ typedef enum enum_table_category TABLE_CATEGORY;
TABLE_CATEGORY get_table_category(const LEX_STRING *db,
const LEX_STRING *name);
+
+typedef struct st_table_field_type
+{
+ LEX_STRING name;
+ LEX_STRING type;
+ LEX_STRING cset;
+} TABLE_FIELD_TYPE;
+
+
+typedef struct st_table_field_def
+{
+ uint count;
+ const TABLE_FIELD_TYPE *field;
+} TABLE_FIELD_DEF;
+
+
+class Table_check_intact
+{
+protected:
+ virtual void report_error(uint code, const char *fmt, ...)= 0;
+
+public:
+ Table_check_intact() {}
+ virtual ~Table_check_intact() {}
+
+ /** Checks whether a table is intact. */
+ bool check(TABLE *table, const TABLE_FIELD_DEF *table_def);
+};
+
+
/*
This structure is shared between different table objects. There is one
instance of table share per one table in the database.
@@ -421,6 +451,18 @@ typedef struct st_table_share
handlerton *default_part_db_type;
#endif
+ /**
+ Cache the checked structure of this table.
+
+ The pointer data is used to describe the structure that
+ a instance of the table must have. Each element of the
+ array specifies a field that must exist on the table.
+
+ The pointer is cached in order to perform the check only
+ once -- when the table is loaded from the disk.
+ */
+ const TABLE_FIELD_DEF *table_field_def_cache;
+
/** place to store storage engine specific data */
void *ha_data;
@@ -1662,17 +1704,6 @@ typedef struct st_open_table_list{
uint32 in_use,locked;
} OPEN_TABLE_LIST;
-typedef struct st_table_field_w_type
-{
- LEX_STRING name;
- LEX_STRING type;
- LEX_STRING cset;
-} TABLE_FIELD_W_TYPE;
-
-
-my_bool
-table_check_intact(TABLE *table, const uint table_f_count,
- const TABLE_FIELD_W_TYPE *table_def);
static inline my_bitmap_map *tmp_use_all_columns(TABLE *table,
MY_BITMAP *bitmap)