Commit d29e7f74 authored by Michael Widenius's avatar Michael Widenius

Fix for Bug #37007 Maria: different checksum for MyISAM table depending on CHECKSUM=0|1

This also adds a check that MyISAM tables with incompatible checksums are detected by CHECK TABLE ... [FOR UPGRADE] and thus also by mysql_upgrade.
The tables that are incomatible are MyISAM tables with ROW_FORMAT=fixed and has VARCHAR fields and have CHECKSUM enabled.
Before these tables gave different checksum if you used CHECK TABLE with or without EXTENDED

mysql-test/r/old-mode.result:
  Now we get same results with and without EXTENDED
mysql-test/r/row-checksum-old.result:
  Initial results
mysql-test/r/row-checksum.result:
  Initial results
mysql-test/t/old-mode.test:
  Added test with QUICK to show that the live checksum is not used when running with --old
mysql-test/t/row-checksum-old-master.opt:
  Start mysqld with --old mode to enable old checksum code
mysql-test/t/row-checksum-old.test:
  Run row-checksum test under mysqld --old
mysql-test/t/row-checksum.test:
  Verify that checksum are calculated the same way with and without EXTENDED
  We run this with several storage engines to ensure results are the same over storage engines
sql/ha_partition.cc:
  Use new HA_HAS_xxx_CHECKSUM flags
sql/handler.cc:
  Use new HA_HAS_xxx_CHECKSUM flags
sql/handler.h:
  Split HA_HAS_CHECKSUM into HA_HAS_NEW_CHECKSUM and HA_HAS_OLD_CHECKSUM flags.
  This is a safe API change as only MyISAM and Maria should use these handler flags.
sql/sql_show.cc:
  Use new HA_HAS_xxx_CHECKSUM flags
sql/sql_table.cc:
  Use file->checksum() for live checksums if the life checksum method corresponds to the mysqld --old flag
storage/maria/ha_maria.cc:
  Use new HA_HAS_xxx_CHECKSUM flags
storage/myisam/ha_myisam.cc:
  Set HA_HAS_OLD_CHECKSUM and/or HA_HAS_NEW_CHECKSUM flags depending on if this is a new myisam or old myisam file
  Add method check_for_upgrade() to detect if the table is of old version with a checksum that is incompatible with CHECK TABLE ... EXTENDED
storage/myisam/ha_myisam.h:
  Added check_for_upgrade()
storage/myisam/mi_open.c:
  Removed not neede cast
  Initialize share->has_null_fields and share->has_varchar_fields variables
storage/myisam/myisamdef.h:
  Added share->has_null_fields and share->has_varchar_fields
parent 9f589947
......@@ -5,8 +5,12 @@ insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, "");
insert t2 select * from t1;
checksum table t1, t2;
Table Checksum
test.t1 3442722830
test.t1 2948697075
test.t2 2948697075
checksum table t1, t2 quick;
Table Checksum
test.t1 NULL
test.t2 NULL
checksum table t1, t2 extended;
Table Checksum
test.t1 2948697075
......
drop table if exists t1;
create table t1 (a int null, v varchar(100)) engine=myisam checksum=0;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
Table Checksum
test.t1 452555338
checksum table t1 quick;
Table Checksum
test.t1 NULL
checksum table t1 extended;
Table Checksum
test.t1 452555338
drop table if exists t1;
create table t1 (a int null, v varchar(100)) engine=myisam checksum=1;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
Table Checksum
test.t1 452555338
checksum table t1 quick;
Table Checksum
test.t1 NULL
checksum table t1 extended;
Table Checksum
test.t1 452555338
drop table if exists t1;
create table t1 (a int null, v varchar(100)) engine=innodb checksum=0;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
Table Checksum
test.t1 452555338
checksum table t1 quick;
Table Checksum
test.t1 NULL
checksum table t1 extended;
Table Checksum
test.t1 452555338
drop table t1;
create table t1 (a int null, v varchar(100)) engine=maria checksum=0;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
Table Checksum
test.t1 452555338
checksum table t1 quick;
Table Checksum
test.t1 NULL
checksum table t1 extended;
Table Checksum
test.t1 452555338
drop table t1;
create table t1 (a int null, v varchar(100)) engine=maria checksum=1;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
Table Checksum
test.t1 452555338
checksum table t1 quick;
Table Checksum
test.t1 NULL
checksum table t1 extended;
Table Checksum
test.t1 452555338
drop table t1;
create table t1 (a int null, v varchar(100)) engine=myisam checksum=1 row_format=fixed;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
Table Checksum
test.t1 4108368782
checksum table t1 quick;
Table Checksum
test.t1 NULL
checksum table t1 extended;
Table Checksum
test.t1 4108368782
drop table if exists t1;
create table t1 (a int null, v varchar(100)) engine=innodb checksum=0 row_format=fixed;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
Table Checksum
test.t1 4108368782
checksum table t1 quick;
Table Checksum
test.t1 NULL
checksum table t1 extended;
Table Checksum
test.t1 4108368782
drop table t1;
drop table if exists t1;
create table t1 (a int null, v varchar(100)) engine=myisam checksum=0;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
Table Checksum
test.t1 229851577
checksum table t1 quick;
Table Checksum
test.t1 NULL
checksum table t1 extended;
Table Checksum
test.t1 229851577
drop table if exists t1;
create table t1 (a int null, v varchar(100)) engine=myisam checksum=1;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
Table Checksum
test.t1 229851577
checksum table t1 quick;
Table Checksum
test.t1 229851577
checksum table t1 extended;
Table Checksum
test.t1 229851577
drop table if exists t1;
create table t1 (a int null, v varchar(100)) engine=innodb checksum=0;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
Table Checksum
test.t1 229851577
checksum table t1 quick;
Table Checksum
test.t1 NULL
checksum table t1 extended;
Table Checksum
test.t1 229851577
drop table t1;
create table t1 (a int null, v varchar(100)) engine=maria checksum=0;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
Table Checksum
test.t1 229851577
checksum table t1 quick;
Table Checksum
test.t1 NULL
checksum table t1 extended;
Table Checksum
test.t1 229851577
drop table t1;
create table t1 (a int null, v varchar(100)) engine=maria checksum=1;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
Table Checksum
test.t1 229851577
checksum table t1 quick;
Table Checksum
test.t1 229851577
checksum table t1 extended;
Table Checksum
test.t1 229851577
drop table t1;
create table t1 (a int null, v varchar(100)) engine=myisam checksum=1 row_format=fixed;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
Table Checksum
test.t1 3885665021
checksum table t1 quick;
Table Checksum
test.t1 3885665021
checksum table t1 extended;
Table Checksum
test.t1 3885665021
drop table if exists t1;
create table t1 (a int null, v varchar(100)) engine=innodb checksum=0 row_format=fixed;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
Table Checksum
test.t1 3885665021
checksum table t1 quick;
Table Checksum
test.t1 NULL
checksum table t1 extended;
Table Checksum
test.t1 3885665021
drop table t1;
......@@ -12,5 +12,6 @@ create table t2 (a int, b varchar(200), c text not null) checksum=0;
insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, "");
insert t2 select * from t1;
checksum table t1, t2;
checksum table t1, t2 quick;
checksum table t1, t2 extended;
drop table t1,t2;
#
# Run row-checksum.test with old mode
#
--source t/row-checksum.test
#
# Test checksum
#
-- source include/have_innodb.inc
-- source include/have_maria.inc
--disable_warnings
drop table if exists t1;
--enable_warnings
create table t1 (a int null, v varchar(100)) engine=myisam checksum=0;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
checksum table t1 quick;
checksum table t1 extended;
drop table if exists t1;
create table t1 (a int null, v varchar(100)) engine=myisam checksum=1;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
checksum table t1 quick;
checksum table t1 extended;
drop table if exists t1;
create table t1 (a int null, v varchar(100)) engine=innodb checksum=0;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
checksum table t1 quick;
checksum table t1 extended;
drop table t1;
create table t1 (a int null, v varchar(100)) engine=maria checksum=0;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
checksum table t1 quick;
checksum table t1 extended;
drop table t1;
create table t1 (a int null, v varchar(100)) engine=maria checksum=1;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
checksum table t1 quick;
checksum table t1 extended;
drop table t1;
#
# These checksums will be different prefixes fixed sizes rows with one extra
# flag byte
#
create table t1 (a int null, v varchar(100)) engine=myisam checksum=1 row_format=fixed;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
checksum table t1 quick;
checksum table t1 extended;
drop table if exists t1;
create table t1 (a int null, v varchar(100)) engine=innodb checksum=0 row_format=fixed;
insert into t1 values(null, null), (1, "hello");
checksum table t1;
checksum table t1 quick;
checksum table t1 extended;
drop table t1;
......@@ -4615,7 +4615,7 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
stat_info->update_time= file->stats.update_time;
stat_info->check_time= file->stats.check_time;
stat_info->check_sum= 0;
if (file->ha_table_flags() & HA_HAS_CHECKSUM)
if (file->ha_table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_NEW_CHECKSUM))
stat_info->check_sum= file->checksum();
return;
}
......
......@@ -3435,7 +3435,7 @@ void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info,
stat_info->update_time= stats.update_time;
stat_info->check_time= stats.check_time;
stat_info->check_sum= 0;
if (table_flags() & (ulong) HA_HAS_CHECKSUM)
if (table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_OLD_CHECKSUM))
stat_info->check_sum= checksum();
return;
}
......
......@@ -107,7 +107,8 @@
#define HA_CAN_FULLTEXT (1 << 21)
#define HA_CAN_SQL_HANDLER (1 << 22)
#define HA_NO_AUTO_INCREMENT (1 << 23)
#define HA_HAS_CHECKSUM (1 << 24)
/* Has automatic checksums and uses the old checksum format */
#define HA_HAS_OLD_CHECKSUM (1 << 24)
/* Table data are stored in separate files (for lower_case_table_names) */
#define HA_FILE_BASED (1 << 26)
#define HA_NO_VARCHAR (1 << 27)
......@@ -124,6 +125,8 @@
*/
#define HA_BINLOG_ROW_CAPABLE (LL(1) << 34)
#define HA_BINLOG_STMT_CAPABLE (LL(1) << 35)
/* Has automatic checksums and uses the new checksum format */
#define HA_HAS_NEW_CHECKSUM (LL(1) << 36)
/*
Set of all binlog flags. Currently only contain the capabilities
......
......@@ -3613,7 +3613,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[16]->set_notnull();
}
if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM)
if (file->ha_table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_NEW_CHECKSUM))
{
table->field[18]->store((longlong) file->checksum(), TRUE);
table->field[18]->set_notnull();
......@@ -4670,7 +4670,7 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
table->field[20]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[20]->set_notnull();
}
if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM)
if (file->ha_table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_NEW_CHECKSUM))
{
table->field[21]->store((longlong) stat_info.check_sum, TRUE);
table->field[21]->set_notnull();
......
......@@ -7287,11 +7287,14 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
}
else
{
if (t->file->ha_table_flags() & HA_HAS_CHECKSUM &&
!(check_opt->flags & T_EXTEND))
/* Call ->checksum() if the table checksum matches 'old_mode' settings */
if (!(check_opt->flags & T_EXTEND) &&
(((t->file->ha_table_flags() & HA_HAS_OLD_CHECKSUM) &&
thd->variables.old_mode) ||
((t->file->ha_table_flags() & HA_HAS_NEW_CHECKSUM) &&
!thd->variables.old_mode)))
protocol->store((ulonglong)t->file->checksum());
else if (!(t->file->ha_table_flags() & HA_HAS_CHECKSUM) &&
(check_opt->flags & T_QUICK))
else if (check_opt->flags & T_QUICK)
protocol->store_null();
else
{
......
......@@ -923,7 +923,7 @@ int ha_maria::open(const char *name, int mode, uint test_if_locked)
int_table_flags|= HA_CAN_INSERT_DELAYED;
}
if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
int_table_flags |= HA_HAS_CHECKSUM;
int_table_flags |= HA_HAS_NEW_CHECKSUM;
for (i= 0; i < table->s->keys; i++)
{
......
......@@ -690,7 +690,19 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked)
if (!table->s->db_record_offset)
int_table_flags|=HA_REC_NOT_IN_SEQ;
if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
int_table_flags|=HA_HAS_CHECKSUM;
{
/*
Set which type of automatic checksum we have
The old checksum and new checksum are identical if there is no
null fields.
Files with new checksum has the HA_OPTION_NULL_FIELDS bit set.
*/
if ((file->s->options & HA_OPTION_NULL_FIELDS) ||
!file->s->has_null_fields)
int_table_flags|= HA_HAS_NEW_CHECKSUM;
if (!(file->s->options & HA_OPTION_NULL_FIELDS))
int_table_flags|= HA_HAS_OLD_CHECKSUM;
}
for (i= 0; i < table->s->keys; i++)
{
......@@ -2042,6 +2054,27 @@ bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info,
return COMPATIBLE_DATA_YES;
}
/**
Check if a table is incompatible with the current version.
The cases are:
- Table has checksum, varchars and are not of dynamic record type
*/
int ha_myisam::check_for_upgrade(HA_CHECK_OPT *check_opt)
{
if (!(file->s->options & HA_OPTION_NULL_FIELDS) &&
!(file->s->options & HA_OPTION_PACK_RECORD) &&
file->s->has_varchar_fields)
{
/* We need alter there to get the HA_OPTION_NULL_FIELDS flag to be set */
return HA_ADMIN_NEEDS_ALTER;
}
return HA_ADMIN_OK;
}
extern int mi_panic(enum ha_panic_function flag);
int myisam_panic(handlerton *hton, ha_panic_function flag)
{
......
......@@ -119,6 +119,7 @@ class ha_myisam: public handler
ulonglong *nb_reserved_values);
int rename_table(const char * from, const char * to);
int delete_table(const char *name);
int check_for_upgrade(HA_CHECK_OPT *check_opt);
int check(THD* thd, HA_CHECK_OPT* check_opt);
int analyze(THD* thd,HA_CHECK_OPT* check_opt);
int repair(THD* thd, HA_CHECK_OPT* check_opt);
......
......@@ -19,6 +19,7 @@
#include "sp_defs.h"
#include "rt_index.h"
#include <m_ctype.h>
#include <mysql_version.h>
#if defined(MSDOS) || defined(__WIN__)
#ifdef __WIN__
......@@ -453,13 +454,20 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
share->rec[i].pack_type=0;
share->rec[i].huff_tree=0;
share->rec[i].offset=offset;
if (share->rec[i].type == (int) FIELD_BLOB)
if (share->rec[i].type == FIELD_BLOB)
{
share->blobs[j].pack_length=
share->rec[i].length - portable_sizeof_char_ptr;
share->blobs[j].offset=offset;
j++;
}
#if MYSQL_VERSION_ID <= 60100
/* This is to detect old checksum option */
if (share->rec[i].null_bit)
share->has_null_fields= 1;
if (share->rec[i].type == FIELD_VARCHAR)
share->has_varchar_fields= 1;
#endif
offset+=share->rec[i].length;
}
share->rec[i].type=(int) FIELD_LAST; /* End marker */
......
......@@ -210,6 +210,9 @@ typedef struct st_mi_isam_share
enum data_file_type data_file_type;
/* Below flag is needed to make log tables work with concurrent insert */
my_bool is_log_table;
/* This is 1 if they table checksum is of old type */
my_bool has_null_fields;
my_bool has_varchar_fields;
my_bool changed, /* If changed since lock */
global_changed, /* If changed since open */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment