MDEV-33658 1/2 Refactoring: extract Key length initialization
mysql_prepare_create_table: Extract a Key initialization part that relates to length calculation and long unique index designation. append_system_key_parts call also moves there. Move this initialization before the duplicate elimination. Extract WITHOUT OVERPLAPS check into a separate function. It had to be moved earlier in the code to preserve the order of the error checks, as in the tests.
This commit is contained in:
parent
e33064e0fc
commit
ecaedbe299
10 changed files with 362 additions and 251 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
586
sql/sql_table.cc
586
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<Key_part_spec> part_it_forwarded(key.columns);
|
||||
List_iterator<Key_part_spec> 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<Key_part_spec> 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));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue