Commit bbe00430 authored by marko's avatar marko

branches/zip: Preserve FOREIGN KEY constraints when creating a PRIMARY KEY.

innodb-index.test: Add some test cases for FOREIGN KEY constraints.

row_merge_rename_tables(): New function,
adapted from row_rename_table_for_mysql().

ha_innobase::add_index(): Use row_merge_rename_tables().
parent 3cc23623
......@@ -8513,10 +8513,11 @@ error_handling:
table as a old table and drop the old table. */
if (new_primary) {
char* old_name = mem_heap_strdup(
heap, innodb_table->name);
char* tmp_table_name = innobase_create_temporary_tablename(
heap, '2', innodb_table->name);
const char* old_name
= innodb_table->name;
const char* tmp_name
= innobase_create_temporary_tablename(heap, '2',
old_name);
trx_start_if_not_started(trx);
......@@ -8527,7 +8528,7 @@ error_handling:
/* Write entry for UNDO */
error = row_undo_report_rename_table_dict_operation(
trx, old_name, indexed_table->name, tmp_table_name);
trx, old_name, indexed_table->name, tmp_name);
if (error != DB_SUCCESS) {
......@@ -8538,15 +8539,10 @@ error_handling:
/* Set the commit flag to FALSE, we will commit the
transaction ourselves, required for UNDO */
error = innobase_rename_table(trx, innodb_table->name,
tmp_table_name, FALSE);
if (error != DB_SUCCESS) {
goto func_exit;
}
error = row_merge_rename_tables(innodb_table, indexed_table,
tmp_name, trx);
error = innobase_rename_table(trx, indexed_table->name,
old_name, FALSE);
if (error != DB_SUCCESS) {
goto func_exit;
......
......@@ -63,6 +63,20 @@ row_merge_drop_indexes(
dict_index_t** index, /* in: indexes to drop */
ulint num_created); /* in: number of elements in index[] */
/*************************************************************************
Rename the tables in the data dictionary. */
ulint
row_merge_rename_tables(
/*====================*/
/* out: error code or DB_SUCCESS */
dict_table_t* old_table, /* in/out: old table, renamed to
tmp_name */
dict_table_t* new_table, /* in/out: new table, renamed to
old_table->name */
const char* tmp_name, /* in: new name for old_table */
trx_t* trx); /* in: transaction handle */
/*************************************************************************
Create a temporary table for creating a primary key, using the definition
of an existing table. */
......
......@@ -469,8 +469,9 @@ create table t1(a int not null, b int not null, c int, primary key (a), key (b))
create table t3(a int not null, c int not null, d int, primary key (a), key (c)) engine = innodb;
create table t4(a int not null, d int not null, e int, primary key (a), key (d)) engine = innodb;
create table t2(a int not null, b int not null, c int not null, d int not null, e int,
primary key (a), foreign key (b) references t1(b), foreign key (c) references t3(c),
foreign key (d) references t4(d)) engine = innodb;
foreign key (b) references t1(b) on delete cascade,
foreign key (c) references t3(c), foreign key (d) references t4(d))
engine = innodb;
alter table t1 drop index b;
ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint
alter table t3 drop index c;
......@@ -481,7 +482,8 @@ alter table t2 drop index b;
ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint
alter table t2 drop index b, drop index c, drop index d;
ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint
set foreign_key_checks=0;
create unique index dc on t2 (d,c);
alter table t2 add primary key (a);
insert into t1 values (1,1,1);
insert into t3 values (1,1,1);
insert into t4 values (1,1,1);
......@@ -497,17 +499,17 @@ t2 CREATE TABLE `t2` (
`d` int(11) NOT NULL,
`e` int(11) DEFAULT NULL,
PRIMARY KEY (`a`),
UNIQUE KEY `dc` (`d`,`c`),
KEY `c` (`c`),
KEY `d` (`d`),
KEY `b` (`b`),
CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`b`),
CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`b`) ON DELETE CASCADE,
CONSTRAINT `t2_ibfk_2` FOREIGN KEY (`c`) REFERENCES `t3` (`c`),
CONSTRAINT `t2_ibfk_3` FOREIGN KEY (`d`) REFERENCES `t4` (`d`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
set foreign_key_checks=1;
set foreign_key_checks=0;
drop table if exists t1,t2,t3,t4;
set foreign_key_checks=1;
delete from t1;
select * from t2;
a b c d e
drop table if exists t2,t1,t3,t4;
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a))
engine = innodb default charset=utf8;
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
......
......@@ -111,8 +111,9 @@ create table t1(a int not null, b int not null, c int, primary key (a), key (b))
create table t3(a int not null, c int not null, d int, primary key (a), key (c)) engine = innodb;
create table t4(a int not null, d int not null, e int, primary key (a), key (d)) engine = innodb;
create table t2(a int not null, b int not null, c int not null, d int not null, e int,
primary key (a), foreign key (b) references t1(b), foreign key (c) references t3(c),
foreign key (d) references t4(d)) engine = innodb;
foreign key (b) references t1(b) on delete cascade,
foreign key (c) references t3(c), foreign key (d) references t4(d))
engine = innodb;
--error ER_DROP_INDEX_FK
alter table t1 drop index b;
--error ER_DROP_INDEX_FK
......@@ -123,7 +124,10 @@ alter table t4 drop index d;
alter table t2 drop index b;
--error ER_DROP_INDEX_FK
alter table t2 drop index b, drop index c, drop index d;
set foreign_key_checks=0;
-- Apparently, the following makes mysql_alter_table() drop index d.
create unique index dc on t2 (d,c);
-- This should preserve the foreign key constraints.
alter table t2 add primary key (a);
insert into t1 values (1,1,1);
insert into t3 values (1,1,1);
insert into t4 values (1,1,1);
......@@ -131,13 +135,10 @@ insert into t2 values (1,1,1,1,1);
commit;
alter table t2 drop index b, add index (b);
show create table t2;
set foreign_key_checks=1;
delete from t1;
select * from t2;
set foreign_key_checks=0;
--disable_warnings
drop table if exists t1,t2,t3,t4;
--enable_warnings
set foreign_key_checks=1;
drop table if exists t2,t1,t3,t4;
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a))
engine = innodb default charset=utf8;
......
......@@ -1657,6 +1657,77 @@ row_merge_rename_index(
return(err);
}
/*************************************************************************
Rename the tables in the data dictionary. */
ulint
row_merge_rename_tables(
/*====================*/
/* out: error code or DB_SUCCESS */
dict_table_t* old_table, /* in/out: old table, renamed to
tmp_name */
dict_table_t* new_table, /* in/out: new table, renamed to
old_table->name */
const char* tmp_name, /* in: new name for old_table */
trx_t* trx) /* in: transaction handle */
{
ulint err = DB_ERROR;
pars_info_t* info;
const char* old_name= old_table->name;
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_ad(old_table != new_table);
trx->op_info = "renaming tables";
trx_start_if_not_started(trx);
/* We use the private SQL parser of Innobase to generate the query
graphs needed in updating the dictionary data in system tables. */
info = pars_info_create();
pars_info_add_str_literal(info, "new_name", new_table->name);
pars_info_add_str_literal(info, "old_name", old_name);
pars_info_add_str_literal(info, "tmp_name", tmp_name);
err = que_eval_sql(info,
"PROCEDURE RENAME_TABLES () IS\n"
"BEGIN\n"
"UPDATE SYS_TABLES SET NAME = :tmp_name\n"
" WHERE NAME = :old_name;\n"
"UPDATE SYS_TABLES SET NAME = :old_name\n"
" WHERE NAME = :new_name;\n"
"END;\n", FALSE, trx);
if (err != DB_SUCCESS) {
goto err_exit;
}
/* The following calls will also rename the .ibd data files if
the tables are stored in a single-table tablespace */
if (!dict_table_rename_in_cache(old_table, tmp_name, FALSE)
|| !dict_table_rename_in_cache(new_table, old_name, FALSE)) {
err = DB_ERROR;
goto err_exit;
}
err = dict_load_foreigns(old_name, TRUE);
if (err != DB_SUCCESS) {
err_exit:
trx->error_state = DB_SUCCESS;
trx_general_rollback_for_mysql(trx, FALSE, NULL);
trx->error_state = DB_SUCCESS;
}
trx->op_info = "";
return(err);
}
/*************************************************************************
Create the index and load in to the dictionary. */
......
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