summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <monty@mysql.com>2004-05-12 00:29:52 +0300
committerunknown <monty@mysql.com>2004-05-12 00:29:52 +0300
commite8bd153f0572e2f3f8f4fb22913d8e885bcd8d72 (patch)
tree11c75fdf1dd0dbc84178dbfbb39f5a584d19d581 /sql
parent76447c6c5bcc4e295b64c087d064f800115459f0 (diff)
downloadmariadb-git-e8bd153f0572e2f3f8f4fb22913d8e885bcd8d72.tar.gz
Don't automaticly generate a new key for a foreign key constraint if there is already a usable key.
Prefer not automatic keys before automatic keys. If there is two conf BitKeeper/etc/ignore: added *.d include/my_base.h: Added flag for automaticly generated key mysql-test/r/constraints.result: Update tests after bug fix mysql-test/r/create.result: Update tests after bug fix mysql-test/r/innodb.result: Added test of automatic creation of foreign keys mysql-test/t/innodb.test: Added test of automatic creation of foreign keys mysql-test/t/key_cache.test: Portability fixes (64 BIT os) sql/sql_acl.cc: Indentation fixes sql/sql_class.cc: Fix key comparison to handle prefix and optionally key segments in different order. sql/sql_class.h: Added flag for automaticly generated keys sql/sql_parse.cc: Added flag for automaticly generated keys sql/sql_table.cc: Don't automaticly generate a new key for a foreign key constraint if there is already a usable key. Prefer not automatic keys before automatic keys. If there is two conflicting automatic keys, prefer the longer one. sql/sql_yacc.yy: Added flag for automaticly generated keys strings/strings-x86.s: Portability fix.
Diffstat (limited to 'sql')
-rw-r--r--sql/sql_acl.cc8
-rw-r--r--sql/sql_class.cc75
-rw-r--r--sql/sql_class.h10
-rw-r--r--sql/sql_parse.cc4
-rw-r--r--sql/sql_table.cc39
-rw-r--r--sql/sql_yacc.yy12
6 files changed, 108 insertions, 40 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index b2d030b523d..9c7fe3e2993 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1918,7 +1918,8 @@ static int replace_column_table(GRANT_TABLE *g_t,
ulong privileges = xx->rights;
bool old_row_exists=0;
key_restore(table,key,0,key_length);
- table->field[4]->store(xx->column.ptr(),xx->column.length(),&my_charset_latin1);
+ table->field[4]->store(xx->column.ptr(),xx->column.length(),
+ &my_charset_latin1);
if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,
0, HA_READ_KEY_EXACT))
@@ -1931,9 +1932,10 @@ static int replace_column_table(GRANT_TABLE *g_t,
continue; /* purecov: inspected */
}
old_row_exists = 0;
- restore_record(table,default_values); // Get empty record
+ restore_record(table,default_values); // Get empty record
key_restore(table,key,0,key_length);
- table->field[4]->store(xx->column.ptr(),xx->column.length(), &my_charset_latin1);
+ table->field[4]->store(xx->column.ptr(),xx->column.length(),
+ &my_charset_latin1);
}
else
{
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index f297ddf2917..03d67c4f300 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -84,26 +84,71 @@ bool key_part_spec::operator==(const key_part_spec& other) const
return length == other.length && !strcmp(field_name, other.field_name);
}
-/* Equality comparison of keys (ignoring name) */
-bool Key::operator==(Key& other)
+
+/*
+ Test if a foreign key is a prefix of the given key
+ (ignoring key name, key type and order of columns)
+
+ NOTES:
+ This is only used to test if an index for a FOREIGN KEY exists
+
+ IMPLEMENTATION
+ We only compare field names
+
+ RETURN
+ 0 Generated key is a prefix of other key
+ 1 Not equal
+*/
+
+bool foreign_key_prefix(Key *a, Key *b)
{
- if (type == other.type &&
- algorithm == other.algorithm &&
- columns.elements == other.columns.elements)
+ /* Ensure that 'a' is the generated key */
+ if (a->generated)
+ {
+ if (b->generated && a->columns.elements > b->columns.elements)
+ swap(Key*, a, b); // Put shorter key in 'a'
+ }
+ else
{
- List_iterator<key_part_spec> col_it1(columns);
- List_iterator<key_part_spec> col_it2(other.columns);
- const key_part_spec *col1, *col2;
- while ((col1 = col_it1++))
+ if (!b->generated)
+ return TRUE; // No foreign key
+ swap(Key*, a, b); // Put generated key in 'a'
+ }
+
+ /* Test if 'a' is a prefix of 'b' */
+ if (a->columns.elements > b->columns.elements)
+ return TRUE; // Can't be prefix
+
+ List_iterator<key_part_spec> col_it1(a->columns);
+ List_iterator<key_part_spec> col_it2(b->columns);
+ const key_part_spec *col1, *col2;
+
+#ifdef ENABLE_WHEN_INNODB_CAN_HANDLE_SWAPED_FOREIGN_KEY_COLUMNS
+ while ((col1= col_it1++))
+ {
+ bool found= 0;
+ col_it2.rewind();
+ while ((col2= col_it2++))
{
- col2 = col_it2++;
- DBUG_ASSERT(col2 != NULL);
- if (!(*col1 == *col2))
- return false;
+ if (*col1 == *col2)
+ {
+ found= TRUE;
+ break;
+ }
}
- return true;
+ if (!found)
+ return TRUE; // Error
+ }
+ return FALSE; // Is prefix
+#else
+ while ((col1= col_it1++))
+ {
+ col2= col_it2++;
+ if (!(*col1 == *col2))
+ return TRUE;
}
- return false;
+ return FALSE; // Is prefix
+#endif
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index a2094d8fe7c..e602b7d6d5f 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -240,14 +240,16 @@ public:
enum ha_key_alg algorithm;
List<key_part_spec> columns;
const char *name;
+ bool generated;
Key(enum Keytype type_par, const char *name_arg, enum ha_key_alg alg_par,
- List<key_part_spec> &cols)
- :type(type_par), algorithm(alg_par), columns(cols), name(name_arg)
+ bool generated_arg, List<key_part_spec> &cols)
+ :type(type_par), algorithm(alg_par), columns(cols), name(name_arg),
+ generated(generated_arg)
{}
~Key() {}
/* Equality comparison of keys (ignoring name) */
- bool operator==(Key& other);
+ friend bool foreign_key_prefix(Key *a, Key *b);
};
class Table_ident;
@@ -265,7 +267,7 @@ public:
foreign_key(const char *name_arg, List<key_part_spec> &cols,
Table_ident *table, List<key_part_spec> &ref_cols,
uint delete_opt_arg, uint update_opt_arg, uint match_opt_arg)
- :Key(FOREIGN_KEY, name_arg, HA_KEY_ALG_UNDEF, cols),
+ :Key(FOREIGN_KEY, name_arg, HA_KEY_ALG_UNDEF, 0, cols),
ref_table(table), ref_columns(cols),
delete_opt(delete_opt_arg), update_opt(update_opt_arg),
match_opt(match_opt_arg)
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 98f6a12ec64..e949d40625d 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3958,13 +3958,13 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
{
lex->col_list.push_back(new key_part_spec(field_name,0));
lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
- lex->col_list));
+ 0, lex->col_list));
lex->col_list.empty();
}
if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
{
lex->col_list.push_back(new key_part_spec(field_name,0));
- lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF,
+ lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF, 0,
lex->col_list));
lex->col_list.empty();
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 55b726293c2..b90ff942cc6 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -679,14 +679,27 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(-1);
}
key_iterator2.rewind ();
- while ((key2 = key_iterator2++) != key)
+ if (key->type != Key::FOREIGN_KEY)
{
- if (*key == *key2)
+ while ((key2 = key_iterator2++) != key)
{
- /* TO DO: issue warning message */
- /* mark that the key should be ignored */
- key->name=ignore_key;
- break;
+ if ((key2->type != Key::FOREIGN_KEY && !foreign_key_prefix(key, key2)))
+ {
+ /* TO DO: issue warning message */
+ /* mark that the generated key should be ignored */
+ if (!key2->generated ||
+ (key->generated && key->columns.elements <
+ key2->columns.elements))
+ key->name= ignore_key;
+ else
+ {
+ /* Remove the previous, generated key */
+ key2->name= ignore_key;
+ key_parts-= key2->columns.elements;
+ (*key_count)--;
+ }
+ break;
+ }
}
}
if (key->name != ignore_key)
@@ -731,14 +744,14 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
switch(key->type){
case Key::MULTIPLE:
- key_info->flags = 0;
+ key_info->flags= 0;
break;
case Key::FULLTEXT:
- key_info->flags = HA_FULLTEXT;
+ key_info->flags= HA_FULLTEXT;
break;
case Key::SPATIAL:
#ifdef HAVE_SPATIAL
- key_info->flags = HA_SPATIAL;
+ key_info->flags= HA_SPATIAL;
break;
#else
my_printf_error(ER_FEATURE_DISABLED,ER(ER_FEATURE_DISABLED),MYF(0),
@@ -749,8 +762,11 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
key_number--; // Skip this key
continue;
default:
- key_info->flags = HA_NOSAME;
+ key_info->flags = HA_NOSAME;
+ break;
}
+ if (key->generated)
+ key_info->flags|= HA_GENERATED_KEY;
key_info->key_parts=(uint8) key->columns.elements;
key_info->key_part=key_part_info;
@@ -774,7 +790,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
*/
/* TODO: Add proper checks if handler supports key_type and algorithm */
- if (key_info->flags == HA_SPATIAL)
+ if (key_info->flags & HA_SPATIAL)
{
if (key_info->key_parts != 1)
{
@@ -2824,6 +2840,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
Key::FULLTEXT : Key::MULTIPLE)),
key_name,
key_info->algorithm,
+ test(key_info->flags & HA_GENERATED_KEY),
key_parts));
}
{
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 0693d33c781..25344fe84cd 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -955,7 +955,7 @@ create:
{
LEX *lex=Lex;
- lex->key_list.push_back(new Key($2,$4.str, $5, lex->col_list));
+ lex->key_list.push_back(new Key($2,$4.str, $5, 0, lex->col_list));
lex->col_list.empty();
}
| CREATE DATABASE opt_if_not_exists ident
@@ -1187,14 +1187,15 @@ key_def:
key_type opt_ident key_alg '(' key_list ')'
{
LEX *lex=Lex;
- lex->key_list.push_back(new Key($1,$2, $3, lex->col_list));
+ lex->key_list.push_back(new Key($1,$2, $3, 0, lex->col_list));
lex->col_list.empty(); /* Alloced by sql_alloc */
}
| opt_constraint constraint_key_type opt_ident key_alg '(' key_list ')'
{
LEX *lex=Lex;
const char *key_name= $3 ? $3:$1;
- lex->key_list.push_back(new Key($2, key_name, $4, lex->col_list));
+ lex->key_list.push_back(new Key($2, key_name, $4, 0,
+ lex->col_list));
lex->col_list.empty(); /* Alloced by sql_alloc */
}
| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
@@ -1206,8 +1207,9 @@ key_def:
lex->fk_delete_opt,
lex->fk_update_opt,
lex->fk_match_option));
- lex->key_list.push_back(new Key(Key::MULTIPLE, $4 ? $4:$1,
- HA_KEY_ALG_UNDEF, lex->col_list));
+ lex->key_list.push_back(new Key(Key::MULTIPLE, $4 ? $4 : $1,
+ HA_KEY_ALG_UNDEF, 1,
+ lex->col_list));
lex->col_list.empty(); /* Alloced by sql_alloc */
}
| constraint opt_check_constraint