From f7356d73910f3df3dedf99d2fafd6413cdb6d33d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Apr 2005 12:16:41 +0300 Subject: [PATCH 1/2] InnoDB: Prevent ALTER TABLE ... ENGINE=... if there are foreign key constraints on the table. (Bug #5574) sql/ha_innodb.cc: Add method can_switch_engines() sql/ha_innodb.h: Add method can_switch_engines() sql/handler.h: Add method can_switch_engines() sql/sql_table.cc: Check handler::can_switch_engines() before switching storage engines --- sql/ha_innodb.cc | 26 ++++++++++++++++++++++++++ sql/ha_innodb.h | 1 + sql/handler.h | 2 ++ sql/sql_table.cc | 4 ++++ 4 files changed, 33 insertions(+) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 3e3a48f4ab9..322d5188a75 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4789,6 +4789,32 @@ ha_innobase::get_foreign_key_create_info(void) return(str); } +/********************************************************************* +Checks if ALTER TABLE may change the storage engine of the table. +Changing storage engines is not allowed for tables for which there +are foreign key constraints (parent or child tables). */ + +bool +ha_innobase::can_switch_engines(void) +/*=================================*/ +{ + row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; + bool can_switch; + + DBUG_ENTER("ha_innobase::can_switch_engines"); + prebuilt->trx->op_info = + "determining if there are foreign key constraints"; + row_mysql_lock_data_dictionary(prebuilt->trx); + + can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list) + && !UT_LIST_GET_FIRST(prebuilt->table->foreign_list); + + row_mysql_unlock_data_dictionary(prebuilt->trx); + prebuilt->trx->op_info = ""; + + DBUG_RETURN(can_switch); +} + /*********************************************************************** Checks if a table is referenced by a foreign key. The MySQL manual states that a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index f10785b695d..edf428669d8 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -161,6 +161,7 @@ class ha_innobase: public handler int check(THD* thd, HA_CHECK_OPT* check_opt); char* update_table_comment(const char* comment); char* get_foreign_key_create_info(); + bool can_switch_engines(); uint referenced_by_foreign_key(); void free_foreign_key_create_info(char* str); THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, diff --git a/sql/handler.h b/sql/handler.h index 50ce33b5067..4c31da6a492 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -450,6 +450,8 @@ public: virtual void append_create_info(String *packet) {} virtual char* get_foreign_key_create_info() { return(NULL);} /* gets foreign key create string from InnoDB */ + /* used in ALTER TABLE; 1 if changing storage engine is allowed */ + virtual bool can_switch_engines() { return 1; } /* used in REPLACE; is > 0 if table is referred by a FOREIGN KEY */ virtual uint referenced_by_foreign_key() { return 0;} virtual void init_table_handle_for_HANDLER() diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5aba764e293..84f51a95691 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3109,6 +3109,10 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, /* Safety fix for innodb */ if (lower_case_table_names) my_casedn_str(files_charset_info, tmp_name); + if (new_db_type != old_db_type && !table->file->can_switch_engines()) { + my_error(ER_ROW_IS_REFERENCED, MYF(0)); + goto err; + } create_info->db_type=new_db_type; if (!create_info->comment) create_info->comment=table->comment; From ebdf2c0153c23b41442cacf4cdf78d499305a748 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 10 Apr 2005 12:40:33 +0500 Subject: [PATCH 2/2] ctype_collate.result, ctype_collate.test, union.result, union.test: fixing tests accordingly item.cc: Allow mixing non-binary collation and binary collation even if coercibility is the same. For easier 4.0 -> 4.1 migrating. sql/item.cc: Allow mixing non-binary collation and binary collation even if coercibility is the same. For easier 4.0 -> 4.1 migrating. mysql-test/t/union.test: fixing tests accordingly mysql-test/r/union.result: fixing tests accordingly mysql-test/t/ctype_collate.test: fixing tests accordingly mysql-test/r/ctype_collate.result: fixing tests accordingly --- mysql-test/r/ctype_collate.result | 13 +++++++++++++ mysql-test/r/union.result | 2 +- mysql-test/t/ctype_collate.test | 12 ++++++++++++ mysql-test/t/union.test | 2 +- sql/item.cc | 11 ++++++++++- 5 files changed, 37 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/ctype_collate.result b/mysql-test/r/ctype_collate.result index bc77e9c2362..cdf890f2c6c 100644 --- a/mysql-test/r/ctype_collate.result +++ b/mysql-test/r/ctype_collate.result @@ -535,6 +535,19 @@ s2 CHAR(5) COLLATE latin1_swedish_ci); SELECT * FROM t1 WHERE s1 = s2; ERROR HY000: Illegal mix of collations (latin1_german1_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation '=' DROP TABLE t1; +CREATE TABLE t1 +(s1 CHAR(5) COLLATE latin1_german1_ci, +s2 CHAR(5) COLLATE latin1_swedish_ci, +s3 CHAR(5) COLLATE latin1_bin); +INSERT INTO t1 VALUES ('a','A','A'); +SELECT * FROM t1 WHERE s1 = s2; +ERROR HY000: Illegal mix of collations (latin1_german1_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation '=' +SELECT * FROM t1 WHERE s1 = s3; +s1 s2 s3 +SELECT * FROM t1 WHERE s2 = s3; +s1 s2 s3 +a A A +DROP TABLE t1; SET NAMES latin1; CREATE TABLE t1 (s1 char(10) COLLATE latin1_german1_ci, diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 96baf36d151..c140ecd26e1 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -1103,7 +1103,7 @@ count(*) drop table t1; create table t2 ( a char character set latin1 collate latin1_swedish_ci, -b char character set latin1 collate latin1_bin); +b char character set latin1 collate latin1_german1_ci); create table t1 as (select a from t2) union (select b from t2); diff --git a/mysql-test/t/ctype_collate.test b/mysql-test/t/ctype_collate.test index 3599beeacc4..b65067a36cf 100644 --- a/mysql-test/t/ctype_collate.test +++ b/mysql-test/t/ctype_collate.test @@ -158,6 +158,18 @@ SELECT * FROM t1 WHERE s1 = s2; DROP TABLE t1; +CREATE TABLE t1 +(s1 CHAR(5) COLLATE latin1_german1_ci, + s2 CHAR(5) COLLATE latin1_swedish_ci, + s3 CHAR(5) COLLATE latin1_bin); +INSERT INTO t1 VALUES ('a','A','A'); +--error 1267 +SELECT * FROM t1 WHERE s1 = s2; +SELECT * FROM t1 WHERE s1 = s3; +SELECT * FROM t1 WHERE s2 = s3; +DROP TABLE t1; + + # # Test that optimizer doesn't use indexes with wrong collation # diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 94cbd71c00c..b0446e1ea4a 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -641,7 +641,7 @@ drop table t1; create table t2 ( a char character set latin1 collate latin1_swedish_ci, -b char character set latin1 collate latin1_bin); +b char character set latin1 collate latin1_german1_ci); --error 1271 create table t1 as (select a from t2) union diff --git a/sql/item.cc b/sql/item.cc index 3b87e5ee2cf..ffde92c4214 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -474,8 +474,17 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags) set(0, DERIVATION_NONE); return 1; } + if (collation->state & MY_CS_BINSORT) + { + return 0; + } + else if (dt.collation->state & MY_CS_BINSORT) + { + set(dt); + return 0; + } CHARSET_INFO *bin= get_charset_by_csname(collation->csname, - MY_CS_BINSORT,MYF(0)); + MY_CS_BINSORT,MYF(0)); set(bin, DERIVATION_NONE); } }