Skip to content

Commit 948bd70

Browse files
committed
Bug#25252847: FOREIGN KEY CONSTRAINTS SHOULD BE CHECKED IN SQL LAYER
The problem was that several storage engine agnostic foreign key constraint checks are currently done inside InnoDB. This requires InnoDB to maintain FK metadata. As a step towards removing this requirement, this patch adds two FK checks to the SQL layer. These checks are: - Disallow FKs on temporary tables. - Disallow index prefixes on FK columns. These two restrictions are already documented, so this patch does not introduce changes of behavior.
1 parent 51bebc9 commit 948bd70

File tree

3 files changed

+23
-4
lines changed

3 files changed

+23
-4
lines changed

sql/key_spec.cc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ bool foreign_key_prefix(const Key_spec *a, const Key_spec *b)
8888
}
8989

9090

91-
bool Foreign_key_spec::validate(THD *thd, List<Create_field> &table_fields) const
91+
bool Foreign_key_spec::validate(THD *thd, const char *table_name,
92+
List<Create_field> &table_fields) const
9293
{
9394
DBUG_ENTER("Foreign_key_spec::validate");
9495

@@ -126,6 +127,13 @@ bool Foreign_key_spec::validate(THD *thd, List<Create_field> &table_fields) cons
126127
}
127128
for (const Key_part_spec *column : columns)
128129
{
130+
// Index prefixes on foreign keys columns are not supported.
131+
if (column->length > 0)
132+
{
133+
my_error(ER_CANNOT_ADD_FOREIGN, MYF(0), table_name);
134+
DBUG_RETURN(true);
135+
}
136+
129137
it.rewind();
130138
while ((sql_field= it++) &&
131139
my_strcasecmp(system_charset_info,

sql/key_spec.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,14 @@ class Foreign_key_spec: public Key_spec
200200
on which the FK is created.
201201
202202
@param thd Thread handle
203+
@param table_name Table name (for error reporting)
203204
@param table_fields List of columns
204205
205206
@retval false Key valid
206207
@retval true Key invalid
207208
*/
208-
bool validate(THD *thd, List<Create_field> &table_fields) const;
209+
bool validate(THD *thd, const char *table_name,
210+
List<Create_field> &table_fields) const;
209211
};
210212

211213
/**

sql/sql_table.cc

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4693,6 +4693,7 @@ static const char* generate_fk_name(const char *table_name,
46934693
Prepare FOREIGN_KEY struct with info about a foreign key.
46944694
46954695
@param thd Thread handle.
4696+
@param create_info Create info from parser.
46964697
@param table_name Table name.
46974698
@param create_list New columns.
46984699
@param existing_fks Array of pre-existing FKs.
@@ -4706,6 +4707,7 @@ static const char* generate_fk_name(const char *table_name,
47064707
*/
47074708

47084709
static bool prepare_foreign_key(THD *thd,
4710+
HA_CREATE_INFO *create_info,
47094711
const char *table_name,
47104712
List<Create_field> *create_list,
47114713
FOREIGN_KEY *existing_fks,
@@ -4717,7 +4719,14 @@ static bool prepare_foreign_key(THD *thd,
47174719
{
47184720
DBUG_ENTER("prepare_foreign_key");
47194721

4720-
if (fk_key->validate(thd, *create_list))
4722+
// FKs are not supported for temporary tables.
4723+
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
4724+
{
4725+
my_error(ER_CANNOT_ADD_FOREIGN, MYF(0), table_name);
4726+
DBUG_RETURN(true);
4727+
}
4728+
4729+
if (fk_key->validate(thd, table_name, *create_list))
47214730
DBUG_RETURN(true);
47224731

47234732
if (fk_key->name.str)
@@ -5298,7 +5307,7 @@ bool mysql_prepare_create_table(THD *thd,
52985307

52995308
if (key->type == KEYTYPE_FOREIGN)
53005309
{
5301-
if (prepare_foreign_key(thd, error_table_name,
5310+
if (prepare_foreign_key(thd, create_info, error_table_name,
53025311
&alter_info->create_list,
53035312
existing_fks, existing_fks_count,
53045313
fk_key_info_buffer, fk_number,

0 commit comments

Comments
 (0)