diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 9580a80e7e76fefab0acf752006852da13a643da..5eee57c250b7dead3ccecbabf30162f76fd191a4 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -2871,8 +2871,12 @@ dict_create_foreign_constraints_low( table2 can be written also with the database name before it: test.table2; the default database is the database of parameter name */ - const char* name) /* in: table full name in the normalized form + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks) + /* in: if TRUE, fail with error code + DB_CANNOT_ADD_CONSTRAINT if any foreign + keys are found. */ { dict_table_t* table; dict_table_t* referenced_table; @@ -2994,6 +2998,18 @@ dict_create_foreign_constraints_low( } if (*ptr == '\0') { + /* The proper way to reject foreign keys for temporary + tables would be to split the lexing and syntactical + analysis of foreign key clauses from the actual adding + of them, so that ha_innodb.cc could first parse the SQL + command, determine if there are any foreign keys, and + if so, immediately reject the command if the table is a + temporary one. For now, this kludge will work. */ + if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) + { + return DB_CANNOT_ADD_CONSTRAINT; + } + /**********************************************************/ /* The following call adds the foreign key constraints to the data dictionary system tables on disk */ @@ -3417,9 +3433,12 @@ dict_create_foreign_constraints( name before it: test.table2; the default database id the database of parameter name */ - const char* name) /* in: table full name in the + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks) /* in: if TRUE, fail with error + code DB_CANNOT_ADD_CONSTRAINT if + any foreign keys are found. */ { char* str; ulint err; @@ -3428,7 +3447,8 @@ dict_create_foreign_constraints( str = dict_strip_comments(sql_string); heap = mem_heap_create(10000); - err = dict_create_foreign_constraints_low(trx, heap, str, name); + err = dict_create_foreign_constraints_low(trx, heap, str, name, + reject_fks); mem_heap_free(heap); mem_free(str); diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index d9cda402bac291257bad4da6b2c689fd5d7d3cf4..a1232acdca7b87ab05614ea1207cdfc707a06b40 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -228,9 +228,12 @@ dict_create_foreign_constraints( name before it: test.table2; the default database id the database of parameter name */ - const char* name); /* in: table full name in the + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks); /* in: if TRUE, fail with error + code DB_CANNOT_ADD_CONSTRAINT if + any foreign keys are found. */ /************************************************************************** Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */ diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index 4e6ff73b0f83d2e28fcb0f49e2e4d780a2536685..a61705b90be3caf87fe81e13f1ed1b449745724e 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -355,9 +355,13 @@ row_table_add_foreign_constraints( FOREIGN KEY (a, b) REFERENCES table2(c, d), table2 can be written also with the database name before it: test.table2 */ - const char* name); /* in: table full name in the + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks); /* in: if TRUE, fail with error + code DB_CANNOT_ADD_CONSTRAINT if + any foreign keys are found. */ + /************************************************************************* The master thread in srv0srv.c calls this regularly to drop tables which we must drop in background after queries to them have ended. Such lazy diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 29239210183546687a72ef94b887d68584c7c48a..26aae117d1db0e612b35530726bb0c88e01b82df 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -2088,9 +2088,12 @@ row_table_add_foreign_constraints( FOREIGN KEY (a, b) REFERENCES table2(c, d), table2 can be written also with the database name before it: test.table2 */ - const char* name) /* in: table full name in the + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks) /* in: if TRUE, fail with error + code DB_CANNOT_ADD_CONSTRAINT if + any foreign keys are found. */ { ulint err; @@ -2111,7 +2114,8 @@ row_table_add_foreign_constraints( trx->dict_operation = TRUE; - err = dict_create_foreign_constraints(trx, sql_string, name); + err = dict_create_foreign_constraints(trx, sql_string, name, + reject_fks); if (err == DB_SUCCESS) { /* Check that also referencing constraints are ok */ diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index d7f7536d401bc5835cf44bc217b29b4bab6326d2..cc074c8ebf5574f3a012675fb8ec0643f50e5b20 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -2527,3 +2527,15 @@ SELECT * FROM t1; id 1 DROP TABLE t2, t1; +CREATE TABLE t1 +( +id INT PRIMARY KEY +) ENGINE=InnoDB; +CREATE TEMPORARY TABLE t2 +( +id INT NOT NULL PRIMARY KEY, +b INT, +FOREIGN KEY (b) REFERENCES test.t1(id) +) ENGINE=InnoDB; +Got one of the listed errors +DROP TABLE t1; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 0bd3d8137a3be0690df4af2d2b3bc3ec93384038..7d449ac926180751a27da529eea1f342fbc34026 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1451,3 +1451,18 @@ TRUNCATE t1; INSERT INTO t1 (id) VALUES (NULL); SELECT * FROM t1; DROP TABLE t2, t1; + +-- Test that foreign keys in temporary tables are not accepted (bug #12084) +CREATE TABLE t1 +( + id INT PRIMARY KEY +) ENGINE=InnoDB; + +--error 1005,1005 +CREATE TEMPORARY TABLE t2 +( + id INT NOT NULL PRIMARY KEY, + b INT, + FOREIGN KEY (b) REFERENCES test.t1(id) +) ENGINE=InnoDB; +DROP TABLE t1; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index aa53b69a6170590614b7135234b555442a98f7f9..4ed5fadb60333bcd764102744e5206fb8a2c81d8 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4687,13 +4687,7 @@ ha_innobase::create( form->s->row_type != ROW_TYPE_REDUNDANT); if (error) { - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); - - trx_free_for_mysql(trx); - - DBUG_RETURN(error); + goto cleanup; } /* Look for a primary key */ @@ -4717,13 +4711,7 @@ ha_innobase::create( error = create_clustered_index_when_no_primary(trx, norm_name); if (error) { - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); - - trx_free_for_mysql(trx); - - DBUG_RETURN(error); + goto cleanup; } } @@ -4732,13 +4720,7 @@ ha_innobase::create( first */ if ((error = create_index(trx, form, norm_name, (uint) primary_key_no))) { - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); - - trx_free_for_mysql(trx); - - DBUG_RETURN(error); + goto cleanup; } } @@ -4747,14 +4729,7 @@ ha_innobase::create( if (i != (uint) primary_key_no) { if ((error = create_index(trx, form, norm_name, i))) { - - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); - - trx_free_for_mysql(trx); - - DBUG_RETURN(error); + goto cleanup; } } } @@ -4767,21 +4742,18 @@ ha_innobase::create( current_thd->query_length, current_thd->charset())) { error = HA_ERR_OUT_OF_MEM; - } else { - error = row_table_add_foreign_constraints(trx, - q.str, norm_name); - - error = convert_error_code_to_mysql(error, NULL); + + goto cleanup; } - if (error) { - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); + error = row_table_add_foreign_constraints(trx, + q.str, norm_name, + create_info->options & HA_LEX_CREATE_TMP_TABLE); - trx_free_for_mysql(trx); + error = convert_error_code_to_mysql(error, NULL); - DBUG_RETURN(error); + if (error) { + goto cleanup; } } @@ -4821,6 +4793,15 @@ ha_innobase::create( trx_free_for_mysql(trx); DBUG_RETURN(0); + +cleanup: + innobase_commit_low(trx); + + row_mysql_unlock_data_dictionary(trx); + + trx_free_for_mysql(trx); + + DBUG_RETURN(error); } /*********************************************************************