diff --git a/mysql-test/suite/binlog/r/binlog_spurious_ddl_errors.result b/mysql-test/suite/binlog/r/binlog_spurious_ddl_errors.result index 798bd8ab853..39c0bd52fac 100644 --- a/mysql-test/suite/binlog/r/binlog_spurious_ddl_errors.result +++ b/mysql-test/suite/binlog/r/binlog_spurious_ddl_errors.result @@ -38,7 +38,7 @@ CREATE TABLE t_stmt (a VARCHAR(100)) ENGINE = EXAMPLE; ALTER TABLE t_stmt ADD COLUMN b INT; CREATE TRIGGER trig_stmt BEFORE INSERT ON t_stmt FOR EACH ROW INSERT INTO t_stmt VALUES (1); CREATE INDEX i ON t_stmt(a); -ERROR 42000: Too many key parts specified; max 0 parts allowed +ERROR 42000: Specified key was too long; max key length is 0 bytes CREATE TABLE t_stmt_new ENGINE = EXAMPLE SELECT * FROM t_stmt; ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-based logging DROP TABLE t_stmt; diff --git a/mysql-test/suite/binlog/t/binlog_spurious_ddl_errors.test b/mysql-test/suite/binlog/t/binlog_spurious_ddl_errors.test index 29a860764a9..5a015c2b8eb 100644 --- a/mysql-test/suite/binlog/t/binlog_spurious_ddl_errors.test +++ b/mysql-test/suite/binlog/t/binlog_spurious_ddl_errors.test @@ -75,7 +75,7 @@ ALTER TABLE t_stmt ADD COLUMN b INT; CREATE TRIGGER trig_stmt BEFORE INSERT ON t_stmt FOR EACH ROW INSERT INTO t_stmt VALUES (1); ---error ER_TOO_MANY_KEY_PARTS +--error ER_TOO_LONG_KEY CREATE INDEX i ON t_stmt(a); --error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE diff --git a/mysql-test/suite/innodb/r/innodb-wl5522-1.result b/mysql-test/suite/innodb/r/innodb-wl5522-1.result index 42c0631dd29..72d7268244f 100644 --- a/mysql-test/suite/innodb/r/innodb-wl5522-1.result +++ b/mysql-test/suite/innodb/r/innodb-wl5522-1.result @@ -659,6 +659,8 @@ NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 15000 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 16000 ALTER TABLE testdb_wl5522.t1 ADD INDEX idx1 (col_1); ALTER TABLE testdb_wl5522.t1 ADD INDEX idx6 (col_1(255)); +Warnings: +Note 1831 Duplicate index `idx6`. This is deprecated and will be disallowed in a future release ALTER TABLE testdb_wl5522.t1 ADD INDEX idx10 (col_10(255)); SELECT col_1 = REPEAT("col1_00001",10), diff --git a/mysql-test/suite/innodb_gis/r/1.result b/mysql-test/suite/innodb_gis/r/1.result index 909051cc54e..9522ab1d41f 100644 --- a/mysql-test/suite/innodb_gis/r/1.result +++ b/mysql-test/suite/innodb_gis/r/1.result @@ -1075,6 +1075,8 @@ col1 POINT, col2 POINT ); CREATE SPATIAL INDEX idx0 ON t2 (col1, col2); +ERROR 42000: Key column 'col1' doesn't exist in table +CREATE SPATIAL INDEX idx0 ON t2 (col0, col2); ERROR HY000: Incorrect arguments to SPATIAL INDEX CREATE TABLE t4 ( col0 INTEGER NOT NULL, diff --git a/mysql-test/suite/innodb_gis/r/point_basic.result b/mysql-test/suite/innodb_gis/r/point_basic.result index bda5ae59238..fd7c8ac180e 100644 --- a/mysql-test/suite/innodb_gis/r/point_basic.result +++ b/mysql-test/suite/innodb_gis/r/point_basic.result @@ -1562,7 +1562,7 @@ ALTER TABLE child ADD FOREIGN KEY(p) REFERENCES parent(p); ERROR HY000: Can't create table `test`.`child` (errno: 150 "Foreign key constraint is incorrectly formed") show warnings; Level Code Message -Warning 150 Alter table `test`.`child` with foreign key (p) constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns. +Warning 150 Alter table `test`.`child` with foreign key (p) constraint failed. There is only prefix index in the referenced table where the referenced columns appear as the first columns. Error 1005 Can't create table `test`.`child` (errno: 150 "Foreign key constraint is incorrectly formed") Warning 1215 Cannot add foreign key constraint for `child` ALTER TABLE parent DROP INDEX idx1; @@ -1570,7 +1570,7 @@ ALTER TABLE child ADD FOREIGN KEY(p) REFERENCES parent(p); Got one of the listed errors show warnings; Level Code Message -Warning 150 Alter table `test`.`child` with foreign key (p) constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns. +Warning 150 Alter table `test`.`child` with foreign key (p) constraint failed. There is only prefix index in the referenced table where the referenced columns appear as the first columns. Error 1005 Can't create table `test`.`child` (errno: 150 "Foreign key constraint is incorrectly formed") Warning 1215 Cannot add foreign key constraint for `child` ALTER TABLE child DROP INDEX idx2; diff --git a/mysql-test/suite/innodb_gis/t/1.test b/mysql-test/suite/innodb_gis/t/1.test index 411cb10602b..711bc971945 100644 --- a/mysql-test/suite/innodb_gis/t/1.test +++ b/mysql-test/suite/innodb_gis/t/1.test @@ -839,8 +839,10 @@ CREATE TABLE t3 ( ); # --error ER_TOO_MANY_KEY_PARTS ---error ER_WRONG_ARGUMENTS +--error ER_KEY_COLUMN_DOES_NOT_EXITS CREATE SPATIAL INDEX idx0 ON t2 (col1, col2); +--error ER_WRONG_ARGUMENTS +CREATE SPATIAL INDEX idx0 ON t2 (col0, col2); CREATE TABLE t4 ( diff --git a/mysql-test/suite/innodb_zip/r/index_large_prefix_8k.result b/mysql-test/suite/innodb_zip/r/index_large_prefix_8k.result index 925bd3f8f9c..4451b149406 100644 --- a/mysql-test/suite/innodb_zip/r/index_large_prefix_8k.result +++ b/mysql-test/suite/innodb_zip/r/index_large_prefix_8k.result @@ -171,9 +171,11 @@ Note 1071 Specified key was too long; max key length is 1536 bytes create index idx3 on worklog5743_8(a2(3072)); Warnings: Note 1071 Specified key was too long; max key length is 1536 bytes +Note 1831 Duplicate index `idx3`. This is deprecated and will be disallowed in a future release show warnings; Level Code Message Note 1071 Specified key was too long; max key length is 1536 bytes +Note 1831 Duplicate index `idx3`. This is deprecated and will be disallowed in a future release create index idx4 on worklog5743_8(a1, a2(1533)); ERROR 42000: Specified key was too long; max key length is 1536 bytes show warnings; @@ -355,6 +357,7 @@ Note 1071 Specified key was too long; max key length is 1536 bytes create index idx2 on worklog5743(a(3072)); Warnings: Note 1071 Specified key was too long; max key length is 1536 bytes +Note 1831 Duplicate index `idx2`. This is deprecated and will be disallowed in a future release SET sql_mode= default; show create table worklog5743; Table Create Table diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 66f689c5312..e6ff4d87690 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -176,7 +176,8 @@ Key::Key(const Key &rhs, MEM_ROOT *mem_root) name(rhs.name), option_list(rhs.option_list), generated(rhs.generated), invisible(false), - without_overlaps(rhs.without_overlaps), old(rhs.old), period(rhs.period) + without_overlaps(rhs.without_overlaps), old(rhs.old), length(rhs.length), + period(rhs.period) { list_copy_and_replace_each_value(columns, mem_root); } diff --git a/sql/sql_class.h b/sql/sql_class.h index 03860e5ff4e..6dcc406e294 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -424,6 +424,7 @@ public: bool invisible; bool without_overlaps; bool old; + uint length; Lex_ident period; Key(enum Keytype type_par, const LEX_CSTRING *name_arg, @@ -431,7 +432,7 @@ public: :DDL_options(ddl_options), type(type_par), key_create_info(default_key_create_info), name(*name_arg), option_list(NULL), generated(generated_arg), - invisible(false), without_overlaps(false), old(false) + invisible(false), without_overlaps(false), old(false), length(0) { key_create_info.algorithm= algorithm_arg; } @@ -442,7 +443,7 @@ public: :DDL_options(ddl_options), type(type_par), key_create_info(*key_info_arg), columns(*cols), name(*name_arg), option_list(create_opt), generated(generated_arg), - invisible(false), without_overlaps(false), old(false) + invisible(false), without_overlaps(false), old(false), length(0) {} Key(const Key &rhs, MEM_ROOT *mem_root); virtual ~Key() = default; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2162850172b..c7ee3f83647 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3558,6 +3558,303 @@ key_add_part_check_null(const handler *file, KEY *key_info, } +static +my_bool key_check_without_overlaps(THD *thd, HA_CREATE_INFO *create_info, + Alter_info *alter_info, + Key &key) +{ + DBUG_ENTER("key_check_without_overlaps"); + if (!key.without_overlaps) + DBUG_RETURN(FALSE); + // append_system_key_parts is already called, so we should check all the + // columns except the last two. + const auto &period_start= create_info->period_info.period.start; + const auto &period_end= create_info->period_info.period.end; + List_iterator part_it_forwarded(key.columns); + List_iterator part_it(key.columns); + part_it_forwarded++; + part_it_forwarded++; + while (part_it_forwarded++) + { + Key_part_spec *key_part= part_it++; + + if (period_start.streq(key_part->field_name) + || period_end.streq(key_part->field_name)) + { + my_error(ER_KEY_CONTAINS_PERIOD_FIELDS, MYF(0), key.name.str, + key_part->field_name.str); + DBUG_RETURN(TRUE); + } + } + + if (key.key_create_info.algorithm == HA_KEY_ALG_HASH || + key.key_create_info.algorithm == HA_KEY_ALG_LONG_HASH) + + { + my_error(ER_KEY_CANT_HAVE_WITHOUT_OVERLAPS, MYF(0), key.name.str); + DBUG_RETURN(TRUE); + } + for (Key &key2: alter_info->key_list) + { + if (key2.type != Key::FOREIGN_KEY) + continue; + DBUG_ASSERT(&key != &key2); + const Foreign_key &fk= (Foreign_key&)key2; + if (fk.update_opt != FK_OPTION_CASCADE) + continue; + for (Key_part_spec& kp: key.columns) + { + for (Key_part_spec& kp2: fk.columns) + { + if (kp.field_name.streq(kp2.field_name)) + { + my_error(ER_KEY_CANT_HAVE_WITHOUT_OVERLAPS, MYF(0), key.name.str); + DBUG_RETURN(TRUE); + } + } + } + } + create_info->period_info.unique_keys++; + + DBUG_RETURN(FALSE); +} + +static +my_bool init_key_part_spec(THD *thd, Alter_info *alter_info, + const handler *file, + const Key &key, Key_part_spec &kp, + uint max_key_length, uint max_key_part_length, + bool *is_hash_field_needed) +{ + DBUG_ENTER("init_key_part_spec"); + + const Lex_ident &field_name= kp.field_name; + Create_field *column= NULL; + + for (Create_field &c: alter_info->create_list) + if (c.field_name.streq(field_name)) + column= &c; + + /* + Either field is not present or field visibility is > INVISIBLE_USER + */ + if (!column || (column->invisible > INVISIBLE_USER && !kp.generated)) + { + my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), field_name.str); + DBUG_RETURN(TRUE); + } + + if (DBUG_EVALUATE_IF("test_invisible_index", 0, 1) + && column->invisible > INVISIBLE_USER + && !(column->flags & VERS_SYSTEM_FIELD) && !key.invisible) + { + my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str); + DBUG_RETURN(TRUE); + } + + const Type_handler *type_handler= column->type_handler(); + switch(key.type) + { + case Key::FULLTEXT: + if (type_handler->Key_part_spec_init_ft(&kp, *column)) + { + my_error(ER_BAD_FT_COLUMN, MYF(0), field_name.str); + DBUG_RETURN(-1); + } + break; + + case Key::SPATIAL: + if (type_handler->Key_part_spec_init_spatial(&kp, *column)) + DBUG_RETURN(TRUE); + break; + + case Key::PRIMARY: + if (column->vcol_info) + { + my_error(ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN, MYF(0)); + DBUG_RETURN(TRUE); + } + if (type_handler->Key_part_spec_init_primary(&kp, *column, file)) + DBUG_RETURN(TRUE); + break; + + case Key::MULTIPLE: + if (type_handler->Key_part_spec_init_multiple(&kp, *column, file)) + DBUG_RETURN(TRUE); + break; + + case Key::FOREIGN_KEY: + if (type_handler->Key_part_spec_init_foreign(&kp, *column, file)) + DBUG_RETURN(TRUE); + break; + + case Key::UNIQUE: + if (type_handler->Key_part_spec_init_unique(&kp, *column, file, + is_hash_field_needed)) + DBUG_RETURN(TRUE); + break; + } + + uint key_part_length= type_handler->calc_key_length(*column); + + if (kp.length) + { + if (f_is_blob(column->pack_flag)) + { + key_part_length= MY_MIN(kp.length, + blob_length_by_type(column->real_field_type()) + * column->charset->mbmaxlen); + if (key_part_length > max_key_length || + key_part_length > max_key_part_length) + { + if (key.type == Key::MULTIPLE) + { + key_part_length= MY_MIN(max_key_length, max_key_part_length); + /* not a critical problem */ + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_TOO_LONG_KEY, ER_THD(thd, ER_TOO_LONG_KEY), + key_part_length); + /* Align key length to multibyte char boundary */ + key_part_length-= key_part_length % column->charset->mbmaxlen; + } + } + } + // Catch invalid use of partial keys + else if (!f_is_geom(column->pack_flag) && + // is the key partial? + kp.length != key_part_length && + // is prefix length bigger than field length? + (kp.length > key_part_length || + // can the field have a partial key? + !type_handler->type_can_have_key_part() || + // a packed field can't be used in a partial key + f_is_packed(column->pack_flag) || + // does the storage engine allow prefixed search? + ((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) && + // and is this a 'unique' key? + (key.type == Key::PRIMARY || key.type == Key::UNIQUE)))) + { + my_message(ER_WRONG_SUB_KEY, ER_THD(thd, ER_WRONG_SUB_KEY), MYF(0)); + DBUG_RETURN(TRUE); + } + else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS)) + key_part_length= kp.length; + } + else if (key_part_length == 0 && (column->flags & NOT_NULL_FLAG) && + !*is_hash_field_needed) + { + my_error(ER_WRONG_KEY_COLUMN, MYF(0), file->table_type(), field_name.str); + DBUG_RETURN(TRUE); + } + if (key_part_length > max_key_part_length && key.type != Key::FULLTEXT) + { + if (key.type == Key::MULTIPLE) + { + key_part_length= max_key_part_length; + /* not a critical problem */ + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_TOO_LONG_KEY, ER_THD(thd, ER_TOO_LONG_KEY), + key_part_length); + /* Align key length to multibyte char boundary */ + key_part_length-= key_part_length % column->charset->mbmaxlen; + } + else if (key.type != Key::UNIQUE) + { + key_part_length= MY_MIN(max_key_length, max_key_part_length); + my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length); + DBUG_RETURN(TRUE); + } + } + + if (key.type == Key::UNIQUE && key_part_length > MY_MIN(max_key_length, + max_key_part_length)) + *is_hash_field_needed= true; + + /* We can not store key_part_length more than 2^16 - 1 in frm. */ + if (*is_hash_field_needed && kp.length > UINT_MAX16) + { + my_error(ER_TOO_LONG_KEYPART, MYF(0), UINT_MAX16); + DBUG_RETURN(TRUE); + } + + kp.length= key_part_length; + + DBUG_RETURN(FALSE); +} + + +/** + @brief Initialize the key length and algorithm (if long hash). + + This function does: + 1. Append system key parts (versioning, periods) + 2. Call Type_handler key_part initialization function. + 3. Determine the length of each key_part. + 4. Calculate the total Key length. + 5. Determine if the key is long unique based on its length + smd result from type handler. It'll be saved in + key_create_info.algorithm as HA_KEY_ALG_LONG_HASH. + + @return FALSE OK + @return TRUE error + */ +static +my_bool init_key_info(THD *thd, Alter_info *alter_info, + HA_CREATE_INFO *create_info, + const handler *file) +{ + DBUG_ENTER("init_key_info"); + uint max_key_length= file->max_key_length(); + uint max_key_part_length= file->max_key_part_length(); + + for (Key &key: alter_info->key_list) + { + if (key.type == Key::FOREIGN_KEY) + continue; + + int parts_added= append_system_key_parts(thd, create_info, &key); + if (parts_added < 0) + DBUG_RETURN(true); + + bool is_hash_field_needed= false; + for (Key_part_spec &kp: key.columns) + { + if (init_key_part_spec(thd, alter_info, file, key, kp, + max_key_length, max_key_part_length, + &is_hash_field_needed)) + DBUG_RETURN(TRUE); + + key.length+= kp.length; + if (key.length > max_key_length && key.type == Key::UNIQUE) + is_hash_field_needed= true; // for case "a BLOB UNIQUE" + + if (key.length > max_key_length && key.type != Key::FULLTEXT && + !is_hash_field_needed) + { + my_error(ER_TOO_LONG_KEY, MYF(0), max_key_length); + DBUG_RETURN(TRUE); + } + + KEY_CREATE_INFO *key_cinfo= &key.key_create_info; + + if (is_hash_field_needed) + { + if (key_cinfo->algorithm == HA_KEY_ALG_UNDEF) + key_cinfo->algorithm= HA_KEY_ALG_LONG_HASH; + + if (key_cinfo->algorithm != HA_KEY_ALG_HASH && + key_cinfo->algorithm != HA_KEY_ALG_LONG_HASH) + { + my_error(ER_TOO_LONG_KEY, MYF(0), max_key_length); + DBUG_RETURN(TRUE); + } + } + } + } + DBUG_RETURN(FALSE); +} + + /* Preparation for table creation @@ -3592,7 +3889,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, { const char *key_name; Create_field *sql_field,*dup_field; - uint field,null_fields,max_key_length; + uint field,null_fields; ulong record_offset= 0; KEY_PART_INFO *key_part_info; int field_no,dup_no; @@ -3603,7 +3900,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, int select_field_count= C_CREATE_SELECT(create_table_mode); bool tmp_table= create_table_mode == C_ALTER_TABLE; const bool create_simple= thd->lex->create_simple(); - bool is_hash_field_needed= false; const Column_derived_attributes dattr(create_info->default_table_charset); const Column_bulk_alter_attributes battr(create_info->alter_table_convert_to_charset); @@ -3639,7 +3935,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, create_info->versioned()); null_fields= 0; create_info->varchar= 0; - max_key_length= file->max_key_length(); /* Handle creation of sequences */ if (create_info->sequence) @@ -3838,6 +4133,9 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, /* special marker for keys to be ignored */ static char ignore_key[1]; + if (init_key_info(thd, alter_info, create_info, file)) + DBUG_RETURN(TRUE); + /* Calculate number of key segements */ *key_count= 0; @@ -3967,10 +4265,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, key_info->name.length= strlen(key_name); key->name= key_info->name; - int parts_added= append_system_key_parts(thd, create_info, key); - if (parts_added < 0) - DBUG_RETURN(true); - key_parts += parts_added; key_info++; } tmp=file->max_keys(); @@ -3989,11 +4283,11 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, key_number=0; for (; (key=key_iterator++) ; key_number++) { - uint key_length=0; Create_field *auto_increment_key= 0; Key_part_spec *column; - is_hash_field_needed= false; + bool is_hash_field_needed= key->key_create_info.algorithm + == HA_KEY_ALG_LONG_HASH; if (key->name.str == ignore_key) { /* ignore redundant keys */ @@ -4004,6 +4298,9 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, break; } + if (key_check_without_overlaps(thd, create_info, alter_info, *key)) + DBUG_RETURN(true); + switch (key->type) { case Key::MULTIPLE: key_info->flags= 0; @@ -4034,10 +4331,12 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, if (key->generated) key_info->flags|= HA_GENERATED_KEY; + key_info->key_length= key->length; key_info->user_defined_key_parts=(uint8) key->columns.elements; key_info->key_part=key_part_info; key_info->usable_key_parts= key_number; key_info->algorithm= key->key_create_info.algorithm; + key_info->without_overlaps= key->without_overlaps; key_info->option_list= key->option_list; extend_option_list(thd, create_info->db_type, !key->old, &key_info->option_list, create_info->db_type->index_options); @@ -4121,37 +4420,11 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, CHARSET_INFO *ft_key_charset=0; // for FULLTEXT for (uint column_nr=0 ; (column=cols++) ; column_nr++) { - Key_part_spec *dup_column; - it.rewind(); field=0; while ((sql_field=it++) && lex_string_cmp(scs, &column->field_name, &sql_field->field_name)) field++; - /* - Either field is not present or field visibility is > INVISIBLE_USER - */ - if (!sql_field || (sql_field->invisible > INVISIBLE_USER && - !column->generated)) - { - my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str); - DBUG_RETURN(TRUE); - } - if (sql_field->invisible > INVISIBLE_USER && - !(sql_field->flags & VERS_SYSTEM_FIELD) && - !key->invisible && DBUG_EVALUATE_IF("test_invisible_index", 0, 1)) - { - my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str); - DBUG_RETURN(TRUE); - } - while ((dup_column= cols2++) != column) - { - if (!lex_string_cmp(scs, &column->field_name, &dup_column->field_name)) - { - my_error(ER_DUP_FIELDNAME, MYF(0), column->field_name.str); - DBUG_RETURN(TRUE); - } - } if (sql_field->compression_method()) { @@ -4161,12 +4434,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, } cols2.rewind(); - switch(key->type) { - + switch(key->type) + { case Key::FULLTEXT: - if (sql_field->type_handler()->Key_part_spec_init_ft(column, - *sql_field) || - (ft_key_charset && sql_field->charset != ft_key_charset)) + if (ft_key_charset && sql_field->charset != ft_key_charset) { my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name.str); DBUG_RETURN(-1); @@ -4174,64 +4445,46 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, ft_key_charset= sql_field->charset; break; - case Key::SPATIAL: - if (sql_field->type_handler()->Key_part_spec_init_spatial(column, - *sql_field) || - sql_field->check_vcol_for_key(thd)) - DBUG_RETURN(TRUE); - if (!(sql_field->flags & NOT_NULL_FLAG)) - { - my_message(ER_SPATIAL_CANT_HAVE_NULL, - ER_THD(thd, ER_SPATIAL_CANT_HAVE_NULL), MYF(0)); - DBUG_RETURN(TRUE); - } - break; - case Key::PRIMARY: - if (sql_field->vcol_info) - { - my_error(ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN, MYF(0)); - DBUG_RETURN(TRUE); - } - if (sql_field->type_handler()->Key_part_spec_init_primary(column, - *sql_field, - file)) - DBUG_RETURN(TRUE); if (!(sql_field->flags & NOT_NULL_FLAG)) { - /* Implicitly set primary key fields to NOT NULL for ISO conf. */ + /* Implicitly set primary key fields to NOT NULL for ISO conformance. */ sql_field->flags|= NOT_NULL_FLAG; sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL; null_fields--; } break; - case Key::MULTIPLE: - if (sql_field->type_handler()->Key_part_spec_init_multiple(column, - *sql_field, - file) || - sql_field->check_vcol_for_key(thd) || - key_add_part_check_null(file, key_info, sql_field, column)) - DBUG_RETURN(TRUE); - break; - - case Key::FOREIGN_KEY: - if (sql_field->type_handler()->Key_part_spec_init_foreign(column, - *sql_field, - file) || - sql_field->check_vcol_for_key(thd) || - key_add_part_check_null(file, key_info, sql_field, column)) - DBUG_RETURN(TRUE); - break; - case Key::UNIQUE: - if (sql_field->type_handler()->Key_part_spec_init_unique(column, - *sql_field, file, - &is_hash_field_needed) || - sql_field->check_vcol_for_key(thd) || - key_add_part_check_null(file, key_info, sql_field, column)) + case Key::MULTIPLE: + case Key::FOREIGN_KEY: + if (key_add_part_check_null(file, key_info, sql_field, column)) + DBUG_RETURN(TRUE); + if (sql_field->check_vcol_for_key(thd)) DBUG_RETURN(TRUE); break; + + case Key::SPATIAL: + if (!(sql_field->flags & NOT_NULL_FLAG)) + { + my_message(ER_SPATIAL_CANT_HAVE_NULL, + ER_THD(thd, ER_SPATIAL_CANT_HAVE_NULL), MYF(0)); + DBUG_RETURN(TRUE); + } + if (sql_field->check_vcol_for_key(thd)) + DBUG_RETURN(TRUE); + break; + } + + for (const Key_part_spec &kp2: key->columns) + { + if (column == &kp2) + break; + if (kp2.field_name.streq(column->field_name)) + { + my_error(ER_DUP_FIELDNAME, MYF(0), column->field_name.str); + DBUG_RETURN(TRUE); + } } if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER) @@ -4246,111 +4499,21 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, key_part_info->fieldnr= field; key_part_info->offset= (uint16) sql_field->offset; key_part_info->key_type=sql_field->pack_flag; - uint key_part_length= sql_field->type_handler()-> - calc_key_length(*sql_field); - - if (column->length) - { - if (f_is_blob(sql_field->pack_flag)) - { - key_part_length= MY_MIN(column->length, - blob_length_by_type(sql_field->real_field_type()) - * sql_field->charset->mbmaxlen); - if (key_part_length > max_key_length || - key_part_length > file->max_key_part_length()) - { - if (key->type == Key::MULTIPLE) - { - key_part_length= MY_MIN(max_key_length, file->max_key_part_length()); - /* not a critical problem */ - push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, - ER_TOO_LONG_KEY, ER_THD(thd, ER_TOO_LONG_KEY), - key_part_length); - /* Align key length to multibyte char boundary */ - key_part_length-= key_part_length % sql_field->charset->mbmaxlen; - } - } - } - // Catch invalid use of partial keys - else if (!f_is_geom(sql_field->pack_flag) && - // is the key partial? - column->length != key_part_length && - // is prefix length bigger than field length? - (column->length > key_part_length || - // can the field have a partial key? - !sql_field->type_handler()->type_can_have_key_part() || - // a packed field can't be used in a partial key - f_is_packed(sql_field->pack_flag) || - // does the storage engine allow prefixed search? - ((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) && - // and is this a 'unique' key? - (key_info->flags & HA_NOSAME)))) - { - my_message(ER_WRONG_SUB_KEY, ER_THD(thd, ER_WRONG_SUB_KEY), MYF(0)); - DBUG_RETURN(TRUE); - } - else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS)) - key_part_length= column->length; - } - else if (key_part_length == 0 && (sql_field->flags & NOT_NULL_FLAG) && - !is_hash_field_needed) - { - my_error(ER_WRONG_KEY_COLUMN, MYF(0), file->table_type(), - column->field_name.str); - DBUG_RETURN(TRUE); - } - if (key_part_length > file->max_key_part_length() && - key->type != Key::FULLTEXT) - { - if (key->type == Key::MULTIPLE) - { - key_part_length= file->max_key_part_length(); - /* not a critical problem */ - push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, - ER_TOO_LONG_KEY, ER_THD(thd, ER_TOO_LONG_KEY), - key_part_length); - /* Align key length to multibyte char boundary */ - key_part_length-= key_part_length % sql_field->charset->mbmaxlen; - } - else - { - if (key->type != Key::UNIQUE) - { - key_part_length= MY_MIN(max_key_length, file->max_key_part_length()); - my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length); - DBUG_RETURN(TRUE); - } - } - } - - if (key->type == Key::UNIQUE - && key_part_length > MY_MIN(max_key_length, - file->max_key_part_length())) - is_hash_field_needed= true; - - /* We can not store key_part_length more then 2^16 - 1 in frm */ - if (is_hash_field_needed && column->length > UINT_MAX16) - { - my_error(ER_TOO_LONG_KEYPART, MYF(0), UINT_MAX16); - DBUG_RETURN(TRUE); - } - else - key_part_info->length= (uint16) key_part_length; + key_part_info->length= column->length; /* Use packed keys for long strings on the first column */ if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) && !((create_info->table_options & HA_OPTION_NO_PACK_KEYS)) && - (key_part_length >= KEY_DEFAULT_PACK_LENGTH) && + (column->length >= KEY_DEFAULT_PACK_LENGTH) && !is_hash_field_needed) { key_info->flags|= sql_field->type_handler()->KEY_pack_flags(column_nr); } /* Check if the key segment is partial, set the key flag accordingly */ - if (key_part_length != sql_field->type_handler()-> + if (column->length != sql_field->type_handler()-> calc_key_length(*sql_field) && - key_part_length != sql_field->type_handler()->max_octet_length()) + column->length != sql_field->type_handler()->max_octet_length()) key_info->flags|= HA_KEY_HAS_PART_KEY_SEG; - key_length+= key_part_length; key_part_info++; } if (!key_info->name.str || check_column_name(key_info->name.str)) @@ -4360,15 +4523,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, } if (key->type == Key::UNIQUE && !(key_info->flags & HA_NULL_PART_KEY)) unique_key=1; - key_info->key_length=(uint16) key_length; - if (key_info->key_length > max_key_length && key->type == Key::UNIQUE) - is_hash_field_needed= true; // for case "a BLOB UNIQUE" - if (key_length > max_key_length && key->type != Key::FULLTEXT && - !is_hash_field_needed) - { - my_error(ER_TOO_LONG_KEY, MYF(0), max_key_length); - DBUG_RETURN(TRUE); - } /* Check long unique keys */ if (is_hash_field_needed) @@ -4380,12 +4534,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, key_info->name.str); DBUG_RETURN(TRUE); } - if (key_info->algorithm != HA_KEY_ALG_UNDEF && - key_info->algorithm != HA_KEY_ALG_HASH ) - { - my_error(ER_TOO_LONG_KEY, MYF(0), max_key_length); - DBUG_RETURN(TRUE); - } } if (is_hash_field_needed || (key_info->algorithm == HA_KEY_ALG_HASH && @@ -4425,40 +4573,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, // Check if a duplicate index is defined. check_duplicate_key(thd, key, key_info, &alter_info->key_list); - key_info->without_overlaps= key->without_overlaps; - if (key_info->without_overlaps) - { - if (key_info->algorithm == HA_KEY_ALG_HASH || - key_info->algorithm == HA_KEY_ALG_LONG_HASH) - - { -without_overlaps_err: - my_error(ER_KEY_CANT_HAVE_WITHOUT_OVERLAPS, MYF(0), key_info->name.str); - DBUG_RETURN(true); - } - key_iterator2.rewind(); - while ((key2 = key_iterator2++)) - { - if (key2->type != Key::FOREIGN_KEY) - continue; - DBUG_ASSERT(key != key2); - Foreign_key *fk= (Foreign_key*) key2; - if (fk->update_opt != FK_OPTION_CASCADE) - continue; - for (Key_part_spec& kp: key->columns) - { - for (Key_part_spec& kp2: fk->columns) - { - if (!lex_string_cmp(scs, &kp.field_name, &kp2.field_name)) - { - goto without_overlaps_err; - } - } - } - } - create_info->period_info.unique_keys++; - } - key_info++; } @@ -4886,20 +5000,6 @@ static int append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info, my_error(ER_PERIOD_NOT_FOUND, MYF(0), key->period.str); return -1; } - - const auto &period_start= create_info->period_info.period.start; - const auto &period_end= create_info->period_info.period.end; - List_iterator part_it(key->columns); - while (Key_part_spec *key_part= part_it++) - { - if (period_start.streq(key_part->field_name) - || period_end.streq(key_part->field_name)) - { - my_error(ER_KEY_CONTAINS_PERIOD_FIELDS, MYF(0), key->name.str, - key_part->field_name.str); - return -1; - } - } const auto &period= create_info->period_info.period; key->columns.push_back(new (thd->mem_root) Key_part_spec(&period.end, 0, true));