res= strconvert(&my_charset_filename, from, FN_REFLEN,
system_charset_info, to, to_length, &errors); if (unlikely(errors)) // Old 5.0 name
{
res= strxnmov(to, to_length, MYSQL50_TABLE_NAME_PREFIX, from, NullS) - to; if (!stay_quiet)
sql_print_error("Invalid (old?) table or database name '%s'", from);
}
void make_tmp_table_name(THD *thd, LEX_STRING *to, constchar *prefix)
{
to->length= my_snprintf((char*) to->str, to->length, "%s-%s-%lx-%llx-%x",
tmp_file_prefix, prefix, current_pid,
thd->thread_id, thd->tmp_table++); if (lower_case_table_names)
{ // Ok to use latin1 as the file name is in the form '#sql-exchange-abc-def'
my_casedn_str_latin1(to->str);
}
}
/* Disable drop of enabled log tables, must be done before name locking */ for (table= tables; table; table= table->next_local)
{ if (check_if_log_table(table, TRUE, "DROP"))
DBUG_RETURN(true);
}
if (!drop_temporary)
{ if (!thd->locked_tables_mode)
{ if (drop_sequence)
{ /* We are trying to drop a sequence. Changealltemporarytablesthatarenotsequencesto normaltablessothatwecantrytodroptheminstead. Ifwedon'tdothis,wewillgetanerror'notasequence' whentryingtodropasequencethatishiddenbyatemporary table.
*/ for (table= tables; table; table= table->next_global)
{ if (table->open_type == OT_TEMPORARY_OR_BASE &&
is_temporary_table(table) && !table->table->s->sequence)
{
thd->mark_tmp_table_as_free_for_reuse(table->table);
table->table= NULL;
}
}
} if (lock_table_names(thd, tables, NULL,
thd->variables.lock_wait_timeout, 0))
DBUG_RETURN(true);
} else
{ for (table= tables; table; table= table->next_local)
{ if (is_temporary_table(table))
{ /* Atemporarytable.
Since'tables'listcan'tcontainduplicates(thisisensured byparser)itissafetocachepointertotheTABLEinstances initselements.
*/
table->table= find_table_for_mdl_upgrade(thd, table->db.str,
table->table_name.str, NULL); if (!table->table)
DBUG_RETURN(true);
table->mdl_request.ticket= table->table->mdl_ticket;
}
}
} /* We remove statistics for table last, after we have the DDL lock */ for (table= tables; table; table= table->next_local)
{
LEX_CSTRING db_name= table->db;
LEX_CSTRING table_name= table->table_name; if (!is_temporary_table(table))
(void) delete_statistics_for_table(thd, &db_name, &table_name);
}
}
/* mark for close and remove all cached entries */
thd->push_internal_handler(&err_handler);
error= mysql_rm_table_no_locks(thd, tables, &thd->db, (DDL_LOG_STATE*) 0,
if_exists, drop_temporary, false, drop_sequence, dont_log_query, false);
thd->pop_internal_handler();
if (unlikely(error))
DBUG_RETURN(TRUE); if (!dont_log_query)
my_ok(thd);
DBUG_RETURN(FALSE);
}
DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table"); if (drop_temporary)
{ /* "DROP TEMPORARY" but a temporary table was not found */
unknown_tables.append(&db);
unknown_tables.append('.');
unknown_tables.append(&table_name);
unknown_tables.append(',');
error= ENOENT; continue;
}
cpath = { path, (size_t)(path_end - path) };
Dummy_error_handler err_handler;
thd->push_internal_handler(&err_handler); if (TABLE_SHARE *share= tdc_acquire_share(thd, table, GTS_TABLE))
{
table_type= share->table_type;
hton= plugin_hton(plugin_lock(thd, share->db_plugin));
version= thd->strmake_lex_custring(share->tabledef_version); if (plugin_ref pp= IF_PARTITIONING(share->default_part_plugin, NULL))
partition_engine_name= thd->strmake_lex_cstring(*plugin_name(pp));
drop_index_from= share->keys;
drop_index_to= share->total_keys;
tdc_release_share(share);
} else
{ switch (err_handler.got_error()) { case ER_WRONG_OBJECT:
table_type= TABLE_TYPE_VIEW; break; case ER_NO_SUCH_TABLE: /* no .frm */
table_type= TABLE_TYPE_UNKNOWN; break; case ER_NOT_FORM_FILE:
{ /* cannotopenthefrm,let'satleastgettheengine seemain.partition_not_blackholeandconnect.drop-open-error
*/ char engine_buf[NAME_CHAR_LEN + 1];
LEX_CSTRING engine= { engine_buf, 0 };
table_type= dd_frm_type(thd, path, &engine, &version); if (table_type == TABLE_TYPE_NORMAL || table_type == TABLE_TYPE_SEQUENCE)
{
plugin_ref p= plugin_lock_by_name(thd, &engine,
MYSQL_STORAGE_ENGINE_PLUGIN);
hton= p ? plugin_hton(p) : NULL;
} break;
} case ER_FAILED_READ_FROM_PAR_FILE: /* no .par file */
hton= partition_hton; /* fall through */ default: /* unreadable (corrupted?) .frm, still need to DROP it */
table_type= TABLE_TYPE_NORMAL;
}
}
thd->pop_internal_handler();
/* Check that we have an exclusive lock on the table to be dropped. */
DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db.str,
table_name.str, MDL_EXCLUSIVE));
// Remove extension for delete
*path_end= '\0';
if (hton && hton->flags & HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE)
log_if_exists= 1;
/* Remove extension for delete */
*path_end= '\0';
ferror= ha_delete_table_force(thd, path, &db, &table_name); if (!ferror)
{
table_dropped= 1;
error= 0;
} if (ferror <= 0)
{
ferror= 0; // Ignore table not found
/* Delete the frm file again (just in case it was rediscovered) */
strmov(path_end, reg_ext); if (mysql_file_delete(key_file_frm, path, MYF(MY_WME|MY_IGNORE_ENOENT)))
ferror= my_errno;
} if (!error)
error= ferror;
}
if (non_temp_tables_count)
query_cache_invalidate3(thd, tables, 0);
if (non_trans_tmp_table_deleted ||
trans_tmp_table_deleted || non_tmp_table_deleted)
{ if (non_trans_tmp_table_deleted || trans_tmp_table_deleted)
thd->transaction->stmt.mark_dropped_temp_table();
if (!dont_log_query && mysql_bin_log.is_open())
{
debug_crash_here("ddl_log_drop_before_binlog"); if (non_trans_tmp_table_deleted)
{ /* Chop of the last comma */
built_non_trans_tmp_query.chop();
built_non_trans_tmp_query.append(generated_by_server);
error |= (thd->binlog_query(THD::STMT_QUERY_TYPE,
built_non_trans_tmp_query.ptr(),
built_non_trans_tmp_query.length(), FALSE, FALSE, is_drop_tmp_if_exists_added, 0) > 0);
} if (trans_tmp_table_deleted)
{ /* Chop of the last comma */
built_trans_tmp_query.chop();
built_trans_tmp_query.append(generated_by_server);
error |= (thd->binlog_query(THD::STMT_QUERY_TYPE,
built_trans_tmp_query.ptr(),
built_trans_tmp_query.length(), TRUE, FALSE, is_drop_tmp_if_exists_added, 0) > 0);
} if (non_tmp_table_deleted)
{
String built_query;
/* historically, rules below apply only to UNIQUE keys */ if (a_flags & HA_NOSAME)
{ /* Long Unique keys should always be last unique key. */
return_if_nonzero((a->algorithm == HA_KEY_ALG_LONG_HASH) -
(b->algorithm == HA_KEY_ALG_LONG_HASH));
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. constauto &period_start= create_info->period_info.period.start; constauto &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++;
const Type_handler *type_handler= column->type_handler(); switch(key.type)
{ case Key::VECTOR: if (type_handler->Key_part_spec_init_vector(&kp, *column))
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "VECTOR INDEX");
DBUG_RETURN(TRUE);
} break; 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;
/* 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);
}
/* Handle creation of sequences */ if (create_info->sequence)
{ if (!(file->ha_table_flags() & HA_CAN_TABLES_WITHOUT_ROLLBACK))
{
my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), file->table_type(),
SEQUENCE_clex_str.str);
DBUG_RETURN(TRUE);
}
/* The user specified fields: check that structure is ok */ if (check_sequence_fields(thd->lex, &alter_info->create_list,
alter_info->db, alter_info->table_name))
DBUG_RETURN(TRUE);
}
for (field_no=0; (sql_field=it++) ; field_no++)
{ if (!(sql_field->flags & NOT_NULL_FLAG))
null_fields++;
/* Check if we have used the same field name before */ for (dup_no=0; (dup_field=it2++) != sql_field; dup_no++)
{ if (sql_field->field_name.streq(dup_field->field_name))
{ /* IfthiswasaCREATE...SELECTstatement,acceptafield redefinitionifwearechangingafieldintheSELECTpart
/* We'remakingonefieldfromtwo,theresultfieldwillhave dup_field->flagsasflags.Ifwe'veincrementednull_fields becauseofsql_field->flags,decrementitback.
*/ if (!(sql_field->flags & NOT_NULL_FLAG))
null_fields--;
if (sql_field->redefine_stage1(dup_field, file))
DBUG_RETURN(true);
it2.remove(); // Remove first (create) definition
select_field_pos--; break;
}
}
} /* Don't pack rows in old tables if the user has requested this */ if ((sql_field->flags & BLOB_FLAG) ||
(sql_field->real_field_type() == MYSQL_TYPE_VARCHAR &&
create_info->row_type != ROW_TYPE_FIXED))
(*db_options)|= HA_OPTION_PACK_RECORD;
it2.rewind();
}
/* record_offset will be increased with 'length-of-null-bits' later */
record_offset= 0;
null_fields+= total_uneven_bit_length;
it.rewind(); while ((sql_field=it++))
{
DBUG_ASSERT(sql_field->charset != 0); if (sql_field->prepare_stage2(file, file->ha_table_flags()))
DBUG_RETURN(TRUE); if (sql_field->real_field_type() == MYSQL_TYPE_VARCHAR)
create_info->varchar= TRUE;
sql_field->offset= record_offset; if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
auto_increment++;
extend_option_list(thd, create_info->db_type, !sql_field->field,
&sql_field->option_list,
file->partition_ht()->field_options); if (parse_option_list(thd, &sql_field->option_struct,
&sql_field->option_list,
file->partition_ht()->field_options, FALSE,
thd->mem_root))
DBUG_RETURN(TRUE); /* Fornowskipfieldsthatarenotphysicallystoredinthedatabase (virtualfields)andupdatetheiroffsetlater (seethenextloop).
*/ if (sql_field->stored_in_db())
record_offset+= sql_field->pack_length;
} /* Update virtual fields' offset and give error if
All fields are invisible */ bool is_all_invisible= true;
it.rewind(); while ((sql_field=it++))
{ if (!sql_field->stored_in_db())
{
sql_field->offset= record_offset;
record_offset+= sql_field->pack_length;
} if (sql_field->invisible == VISIBLE)
is_all_invisible= false;
} if (is_all_invisible)
{
my_error(ER_TABLE_MUST_HAVE_COLUMNS, MYF(0));
DBUG_RETURN(TRUE);
} if (auto_increment > 1)
{
my_message(ER_WRONG_AUTO_KEY, ER_THD(thd, ER_WRONG_AUTO_KEY), MYF(0));
DBUG_RETURN(TRUE);
} if (auto_increment &&
(file->ha_table_flags() & HA_NO_AUTO_INCREMENT))
{
my_error(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT, MYF(0), file->table_type());
DBUG_RETURN(TRUE);
}
if (init_key_info(thd, alter_info, create_info, file))
DBUG_RETURN(TRUE);
/* Calculate number of key segments */
*key_count= 0;
while ((key=key_iterator++))
{
DBUG_PRINT("info", ("key name: '%s' type: %d", key->name.str ? key->name.str : "(none)" , key->type)); if (key->type == Key::FOREIGN_KEY)
{
Foreign_key *fk_key= (Foreign_key*) key; if (fk_key->validate(alter_info->create_list))
DBUG_RETURN(TRUE); if (fk_key->ref_columns.elements)
{ if (fk_key->ref_columns.elements != fk_key->columns.elements)
{
my_error(ER_WRONG_FK_DEF, MYF(0),
(fk_key->name.str ? fk_key->name.str : "foreign key without name"),
ER_THD(thd, ER_KEY_REF_DO_NOT_MATCH_TABLE_REF));
DBUG_RETURN(TRUE);
}
} else
fk_key->ref_columns.append(&fk_key->columns); continue;
}
(*key_count)++;
tmp=file->max_key_parts(); if (key->columns.elements > tmp)
{
my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp);
DBUG_RETURN(TRUE);
} if (check_ident_length(&key->name))
DBUG_RETURN(TRUE);
key_iterator2.rewind (); if (key->type != Key::FOREIGN_KEY)
{ while ((key2 = key_iterator2++) != key)
{ /* is_foreign_key_prefix(key,key2)returnstrueifkeyorkey2,or both,is'generated',andageneratedkeyisaprefixoftheother key.Thenwedonotneedthegeneratedshorterkey.
*/ if (key2->type != Key::FOREIGN_KEY && key2->type != Key::IGNORE_KEY &&
is_foreign_key_prefix(key, key2))
{ /* mark that the generated key should be ignored */ if (!key2->generated ||
(key->generated && key->columns.elements <
key2->columns.elements))
key->type= Key::IGNORE_KEY; else
{
key2->type= Key::IGNORE_KEY;
key_parts-= key2->columns.elements;
(*key_count)--;
} break;
}
}
} if (key->type != Key::IGNORE_KEY)
key_parts+=key->columns.elements; else
(*key_count)--; if (key->name.str && !tmp_table && (key->type != Key::PRIMARY) &&
key->name.streq(primary_key_name))
{
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
DBUG_RETURN(TRUE);
} if (key->type == Key::PRIMARY && key->name.str &&
!key->name.streq(primary_key_name))
{ bool sav_abort_on_warning= thd->abort_on_warning;
thd->abort_on_warning= FALSE; /* Don't make an error out of this. */
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_WRONG_NAME_FOR_INDEX, "Name '%-.100s' ignored for PRIMARY key.",
key->name.str);
thd->abort_on_warning= sav_abort_on_warning;
}
}
KEY *key_info= *key_info_buffer= thd->calloc<KEY>(*key_count); if (!*key_info_buffer)
DBUG_RETURN(true); // Out of memory
key_iterator.rewind(); while ((key=key_iterator++))
{ if (key->type == Key::IGNORE_KEY)
{ /* The key was replaced by another key */ if (!create_info->tmp_table() &&
alter_info->add_stat_drop_index(thd, &key->name))
DBUG_RETURN(true); continue;
} if (key->type == Key::FOREIGN_KEY) continue; /* Create the key name based on the first column (if not given) */ if (key->type == Key::PRIMARY)
{ if (primary_key)
{
my_message(ER_MULTIPLE_PRI_KEY, ER_THD(thd, ER_MULTIPLE_PRI_KEY),
MYF(0));
DBUG_RETURN(true);
}
key_name= primary_key_name;
primary_key=1;
} elseif (!(key_name= key->name).str)
{
Lex_ident_column field_name(key->columns.elem(0)->field_name);
it.rewind(); while ((sql_field=it++) &&
!field_name.streq(sql_field->field_name))
{ } if (sql_field)
field_name= sql_field->field_name;
key_name= make_unique_key_name(thd, field_name,
*key_info_buffer, key_info);
} if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
{
my_error(ER_DUP_KEYNAME, MYF(0), key_name.str);
DBUG_RETURN(true);
}
/* TODO: Add proper checks if handler supports key_type and algorithm */ if (key_info->algorithm == HA_KEY_ALG_RTREE)
{ if (!(file->ha_table_flags() & HA_CAN_RTREEKEYS))
{
my_error(ER_TABLE_CANT_HANDLE_SPKEYS, MYF(0), file->table_type());
DBUG_RETURN(TRUE);
} if (key->type != Key::SPATIAL || key_info->user_defined_key_parts != 1)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "RTREE INDEX");
DBUG_RETURN(TRUE);
}
}
/* Take block size from key part or table part */ /* TODO:Addwarningifblocksizechanges.Wecan'tdoithere,as thismaydependonthesizeofthekey
*/
key_info->block_size= (key->key_create_info.block_size ?
key->key_create_info.block_size :
create_info->key_block_size);
List_iterator<Key_part_spec> cols(key->columns), cols2(key->columns);
CHARSET_INFO *ft_key_charset=0; // for FULLTEXT for (uint column_nr=0 ; (column=cols++) ; column_nr++)
{
it.rewind();
field=0; while ((sql_field=it++) &&
!column->field_name.streq(sql_field->field_name))
field++;
if (sql_field->compression_method())
{
my_error(ER_COMPRESSED_COLUMN_USED_AS_KEY, MYF(0),
column->field_name.str);
DBUG_RETURN(TRUE);
}
cols2.rewind(); switch(key->type)
{ case Key::VECTOR: if (sql_field->check_vcol_for_key(thd))
DBUG_RETURN(TRUE); if (!(sql_field->flags & NOT_NULL_FLAG))
{
my_error(ER_INDEX_CANNOT_HAVE_NULL, MYF(0), "VECTOR");
DBUG_RETURN(TRUE);
} if (create_info->tmp_table())
{
my_error(ER_NO_INDEX_ON_TEMPORARY, MYF(0), "VECTOR",
file->table_type());
DBUG_RETURN(TRUE);
} break; case Key::FULLTEXT: 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);
}
ft_key_charset= sql_field->charset; break;
case Key::PRIMARY: if (!(sql_field->flags & NOT_NULL_FLAG))
{ /* 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::UNIQUE: 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::IGNORE_KEY: break;
case Key::SPATIAL: if (!(sql_field->flags & NOT_NULL_FLAG))
{
my_error(ER_INDEX_CANNOT_HAVE_NULL, MYF(0), "SPATIAL");
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)
{
DBUG_ASSERT(key->type != Key::FULLTEXT);
DBUG_ASSERT(key->type != Key::SPATIAL); if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY))
auto_increment--; // Field is used
auto_increment_key= sql_field;
}
/* For SPATIAL, FULLTEXT and HASH indexes (anything other than B-tree),
ignore the ASC/DESC attribute of columns. */ if (key_info->algorithm > HA_KEY_ALG_BTREE)
column->asc= true; // ignore DESC
key_part_info->fieldnr= field;
key_part_info->offset= (uint16) sql_field->offset;
key_part_info->key_type=sql_field->pack_flag;
key_part_info->key_part_flag= column->asc ? 0 : HA_REVERSE_SORT;
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)) &&
(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 (column->length != sql_field->type_handler()->
calc_key_length(*sql_field) &&
column->length != sql_field->type_handler()->max_octet_length())
key_info->flags|= HA_KEY_HAS_PART_KEY_SEG;
if ((flags & BLOB_FLAG) && length)
{ if (real_field_type() == FIELD_TYPE_BLOB ||
real_field_type() == FIELD_TYPE_TINY_BLOB ||
real_field_type() == FIELD_TYPE_MEDIUM_BLOB)
{ /* The user has given a length to the blob column */
set_handler(Type_handler::blob_type_handler((uint) length));
pack_length= type_handler()->calc_pack_length(0);
}
length= 0;
}
DBUG_RETURN(0);
}
/* ifdiscoveryfailed,thepluginwillbeauto-unlocked,asit waslockedontheTHD,seeabove. ifdiscoverysucceeded,thepluginwasreplacedbyaglobally lockedplugin,thatwillbeunlockedbyfree_table_share()
*/ if (ha_err)
share.db_plugin= 0; // will be auto-freed, locked above on the THD
if (!table)
{
(void) thd->rm_temporary_table(create_info->db_type, path.str); goto err;
}
if (is_trans != NULL)
*is_trans= table->file->has_transactions();
thd->reset_sp_cache= true;
thd->used|= THD::THREAD_SPECIFIC_USED;
create_info->table= table; // Store pointer to table
}
error= 0;
err: if (unlikely(error) && ddl_log_state_create)
{ /* Table was never created, so we can ignore the ddl log entry */
ddl_log_complete(ddl_log_state_create);
}
if (used_engine)
{
db_type= thd->lex->create_info.db_type->db_type; // Currently any dynamic storage engine is not possible to identify // using DB_TYPE_XXXX and ENGINE=SEQUENCE is one of them. // Therefore, we get storage engine name from lex.
engine_name=
thd->lex->m_sql_cmd->option_storage_engine_name()->name();
} else
{ const handlerton *hton= ha_default_handlerton(thd);
db_type= hton->db_type;
engine_name= hton_name(hton);
}
// In Galera cluster we support only InnoDB sequences if (db_type != DB_TYPE_INNODB)
{ // (1) CREATE TABLE ... ENGINE=SEQUENCE OR // (2) ALTER TABLE ... ENGINE= OR // Note in ALTER TABLE table->s->sequence != nullptr // (3) CREATE SEQUENCE ... ENGINE= if ((thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
lex_string_eq(engine_name, STRING_WITH_LEN("SEQUENCE"))) ||
(thd->lex->sql_command == SQLCOM_ALTER_TABLE) ||
(thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE))
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "non-InnoDB sequences in Galera cluster");
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_NOT_SUPPORTED_YET, "ENGINE=%s not supported by Galera",
engine_name->str); return(true);
}
}
// In Galera cluster it is best to use INCREMENT BY 0 with CACHE // or NOCACHE if (seq &&
seq->increment &&
seq->cache)
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "CACHE without INCREMENT BY 0 in Galera cluster"); return(true);
}
return (false);
}
/** Additional CREATE TABLE/SEQUENCE checks for Galera cluster.
/* Copy temporarily the statement flags to thd for lock_table_names() */
save_thd_create_info_options= thd->lex->create_info.options;
thd->lex->create_info.options|= create_info->options;
/* Open or obtain an exclusive metadata lock on table being created */
create_table->db_type= 0;
result= open_and_lock_tables(thd, *create_info, create_table, FALSE, 0);
if (result)
{ if (thd->slave_thread &&
!thd->is_error() && create_table->db_type &&
(create_table->db_type->flags & HTON_IGNORE_UPDATES))
{ /* Table existed in distributed engine. Log query to binary log */
result= 0; goto err;
} /* is_error() may be 0 if table existed and we generated a warning */
DBUG_RETURN(thd->is_error());
} /* The following is needed only in case of lock tables */ if ((create_info->table= create_table->table))
{
pos_in_locked_tables= create_info->table->pos_in_locked_tables;
mdl_ticket= create_table->table->mdl_ticket;
}
/* In RBR or readonly server we don't need to log CREATE TEMPORARY TABLE */ if (!result && create_info->tmp_table() && !thd->binlog_create_tmp_table())
{ /* Notethatmark_created_temp_tablewasnotcalledandthus table->s->table_creation_was_loggedisnotset!
*/
DBUG_RETURN(result);
}
if (create_info->tmp_table())
thd->transaction->stmt.mark_created_temp_table();
/* Write log if no error or if we already deleted a table */ if (!result || thd->log_current_statement())
{ if (unlikely(result) && create_info->table_was_deleted &&
pos_in_locked_tables)
{ /* Possiblelockedtablewasdropped.Weshouldremovemetadatalocks associatedwithitanddoUNLOCK_TABLESifnomorelockedtables.
*/
(void) thd->locked_tables_list.unlock_locked_table(thd, mdl_ticket);
} elseif (likely(!result) && create_info->table)
{ /* Rememberthattablecreationwasloggedsothatweknowif weshouldlogadeleteofit. Ifcreate_info->tablewasnotset,it'sanormaltableand table_creation_was_loggedwillbesetwhentheshareiscreated.
*/
create_info->table->s->table_creation_was_logged= 1;
}
thd->binlog_xid= thd->query_id;
ddl_log_update_xid(&ddl_log_state_create, thd->binlog_xid); if (ddl_log_state_rm.is_active())
ddl_log_update_xid(&ddl_log_state_rm, thd->binlog_xid);
debug_crash_here("ddl_log_create_before_binlog"); if (unlikely(write_bin_log(thd, result ? FALSE : TRUE, thd->query(),
thd->query_length(), is_trans)))
result= 1;
debug_crash_here("ddl_log_create_after_binlog");
thd->binlog_xid= 0;
if (res)
{ /* is_error() may be 0 if table existed and we generated a warning */
res= thd->is_error();
src_table_exists= !res; goto err;
} /* Ensure we don't try to create something from which we select from */ if (create_info->or_replace() && !create_info->tmp_table())
{
TABLE_LIST *duplicate; if ((duplicate= unique_table(thd, table, src_table, 0)))
{
update_non_unique_table_error(src_table, "CREATE", duplicate);
res= 1; goto err;
}
}
src_table->table->use_all_columns();
DEBUG_SYNC(thd, "create_table_like_after_open");
/* FillTable_specification_standAlter_infowiththesourcetabledescription. SetORREPLACEandIFNOTEXISTSoptionasintheCREATETABLELIKE statement.
*/
local_create_info.init(create_info->create_like_options());
local_create_info.db_type= src_table->table->s->db_type();
local_create_info.row_type= src_table->table->s->row_type;
local_create_info.alter_info= &local_alter_info; /* Thisstatement: CREATETABLEt1LIKEt2 doesnotsupporttablecharset/collationclauses. Noneedstocopy.Asserttheyareempty.
*/
DBUG_ASSERT(create_info->default_charset_collation.is_empty());
DBUG_ASSERT(create_info->convert_charset_collation.is_empty()); if (mysql_prepare_alter_table(thd, src_table->table, &local_create_info,
&local_alter_info, &local_alter_ctx)) goto err; #ifdef WITH_PARTITION_STORAGE_ENGINE /* Partition info is not handled by mysql_prepare_alter_table() call. */ if (src_table->table->part_info)
{ /* TheCREATETABLELIKEshouldnotinherittheDATADIRECTORY andINDEXDIRECTORYfromthebasetable. SothatTRUEargumentfortheget_clone.
*/
thd->work_part_info= src_table->table->part_info->get_clone(thd, TRUE);
} #endif/*WITH_PARTITION_STORAGE_ENGINE*/
SimilarlytoSHOWCREATETABLEweignoreMAX_ROWSattributeof temporarytablewhichrepresentsI_Stable.
*/ if (src_table->schema_table)
local_create_info.max_rows= 0; /* Replace type of source table with one specified in the statement. */
local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
local_create_info.options|= create_info->options; /* Reset auto-increment counter for the new table. */
local_create_info.auto_increment_value= 0; /* DonotinheritvaluesofDATAandINDEXDIRECTORYoptionsfrom theoriginaltable.Thisisdocumentedbehavior.
*/
local_create_info.data_file_name= local_create_info.index_file_name= NULL;
/* The following is needed only in case of lock tables */ if ((local_create_info.table= thd->lex->query_tables->table))
pos_in_locked_tables= local_create_info.table->pos_in_locked_tables;
res= ((create_res=
mysql_create_table_no_lock(thd,
&ddl_log_state_create, &ddl_log_state_rm,
&local_create_info, &local_alter_info,
&is_trans, C_ORDINARY_CREATE,
table)) > 0); /* Remember to log if we deleted something */
do_logging= thd->log_current_statement(); if (res) goto err;
if (thd->is_binlog_format_row() || force_generated_create)
{ /* Sincetemporarytablesarenotreplicatedunderrow-based replication,CREATETABLE...LIKE...needsspecial treatment.Wehavesomecasestoconsider,accordingtothe followingdecisiontable:
==================================================== CaseTargetSourceWritetobinarylog ==================================================== 1normalnormalOriginalstatement 2normaltemporaryGeneratedstatementifthetable wascreated. 3temporarynormalNothing 4temporarytemporaryNothing 5anysharedGeneratedstatementifthetable wascreatedifenginechanged ====================================================
*/ if (!(create_info->tmp_table()) || force_generated_create)
{ // Case 2 & 5 if (src_table->table->s->tmp_table || force_generated_create)
{ char buf[2048];
String query(buf, sizeof(buf), system_charset_info);
query.length(0); // Have to zero it since constructor doesn't
Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN |
MYSQL_OPEN_IGNORE_KILLED); bool new_table= FALSE; // Whether newly created table is open.
if (create_res != 0)
{ /* Tableorviewwithsamenamealreadyexistedandwewhereusing IFEXISTS.Continuewithoutlogginganything.
*/
do_logging= 0; goto err;
} if (!table->table)
{ if (local_create_info.table)
{ /* Thetablewasatemporarytableorageneratedtable.Usethesrcas thetabledefinition.
*/
table->table= local_create_info.table;
} else
{
TABLE_LIST::enum_open_strategy save_open_strategy; int open_res; /* Force the newly created table to be opened */
save_open_strategy= table->open_strategy;
table->open_strategy= TABLE_LIST::OPEN_NORMAL;
/* The ALTER TABLE is always in its own transaction */
error= trans_commit_stmt(thd); if (unlikely(trans_commit_implicit(thd)))
error=1; if (likely(!error))
error= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
err:
thd->tablespace_op=FALSE;
if (mdl_downgrade > MDL_NOT_INITIALIZED)
table->mdl_ticket->downgrade_lock(mdl_downgrade);
if (likely(error == 0))
{
my_ok(thd);
DBUG_RETURN(0);
}
if (remove_drop)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_CANT_DROP_FIELD_OR_KEY,
ER_THD(thd, ER_CANT_DROP_FIELD_OR_KEY),
drop->type_name(), drop->name.str);
drop_it.remove();
} else
left_flags|= cur_flag;
} /* Reset state to what's left in drop list */
alter_info->flags&= ~(ALTER_PARSER_DROP_COLUMN |
ALTER_DROP_INDEX |
ALTER_DROP_FOREIGN_KEY);
alter_info->flags|= left_flags;
}
/* Handle RENAME KEY IF EXISTS. */
{
List_iterator<Alter_rename_key> rename_key_it(alter_info->alter_rename_key_list);
Alter_rename_key *rename_key; while ((rename_key= rename_key_it++))
{ if (!rename_key->alter_if_exists) continue; bool exists= false; for (uint n_key= 0; n_key < table->s->total_keys; n_key++)
{ if (table->key_info[n_key].name.streq(rename_key->old_name))
{
exists= true; break;
}
} if (exists) continue;
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_KEY_DOES_NOT_EXISTS,
ER_THD(thd, ER_KEY_DOES_NOT_EXISTS),
rename_key->old_name.str, table->s->table_name.str);
rename_key_it.remove();
}
} /* Handle ALTER KEY IF EXISTS. */
{
List_iterator<Alter_index_ignorability> ignor_it(alter_info->alter_index_ignorability_list);
Alter_index_ignorability *aii; while ((aii= ignor_it++))
{ if (!aii->if_exists()) continue; bool exists= false; for (uint n_key= 0; n_key < table->s->total_keys; n_key++)
{ if (table->key_info[n_key].name.streq(aii->name()))
{
exists= true; break;
}
} if (exists) continue;
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_KEY_DOES_NOT_EXISTS,
ER_THD(thd, ER_KEY_DOES_NOT_EXISTS),
aii->name().str, table->s->table_name.str);
ignor_it.remove();
}
} /* ALTER TABLE ADD KEY IF NOT EXISTS */ /* ALTER TABLE ADD FOREIGN KEY IF NOT EXISTS */
{
Key *key;
List_iterator<Key> key_it(alter_info->key_list);
uint n_key;
Lex_ident_column keyname; while ((key=key_it++))
{ if (!key->if_not_exists() && !key->or_replace()) continue;
/* Check if the table already has a PRIMARY KEY */ bool dup_primary_key=
key->type == Key::PRIMARY &&
table->s->primary_key != MAX_KEY &&
(keyname= table->s->key_info[table->s->primary_key].name).str &&
table->s->key_info[table->s->primary_key].name.
streq(primary_key_name); if (dup_primary_key) goto remove_key;
/* If the name of the key is not specified, */ /* let us check the name of the first key part. */ if ((keyname= key->name).str == NULL)
{ if (key->type == Key::PRIMARY)
keyname= primary_key_name; else
{
List_iterator<Key_part_spec> part_it(key->columns);
Key_part_spec *kp; if ((kp= part_it++))
keyname= kp->field_name; if (keyname.str == NULL) continue;
}
} if (key->type != Key::FOREIGN_KEY)
{ for (n_key=0; n_key < table->s->total_keys; n_key++)
{ if (table->key_info[n_key].name.streq(keyname))
{ goto remove_key;
}
}
} else
{
List <FOREIGN_KEY_INFO> fk_child_key_list;
FOREIGN_KEY_INFO *f_key;
table->file->get_foreign_key_list(thd, &fk_child_key_list);
List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_child_key_list); while ((f_key= fk_key_it++))
{ if (Lex_ident_column(*f_key->foreign_id).streq(keyname)) goto remove_key;
}
}
{
Key *chk_key;
List_iterator<Key> chk_it(alter_info->key_list);
Lex_ident_column chkname; while ((chk_key=chk_it++) && chk_key != key)
{ if ((chkname= chk_key->name).str == NULL)
{
List_iterator<Key_part_spec> part_it(chk_key->columns);
Key_part_spec *kp; if ((kp= part_it++))
chkname= kp->field_name; if (chkname.str == NULL) continue;
} if (key->type == chk_key->type &&
chkname.streq(keyname)) goto remove_key;
}
} continue;
remove_key: if (key->if_not_exists())
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_DUP_KEYNAME, ER_THD(thd, dup_primary_key
? ER_MULTIPLE_PRI_KEY : ER_DUP_KEYNAME),
keyname.str);
key_it.remove(); if (key->type == Key::FOREIGN_KEY)
{ /* ADD FOREIGN KEY appends two items. */
key_it.remove();
} if (alter_info->key_list.is_empty())
alter_info->flags&= ~(ALTER_ADD_INDEX | ALTER_ADD_FOREIGN_KEY);
} else
{
DBUG_ASSERT(key->or_replace());
Alter_drop::drop_type type= (key->type == Key::FOREIGN_KEY) ?
Alter_drop::FOREIGN_KEY : Alter_drop::KEY;
Alter_drop *ad= new (thd->mem_root) Alter_drop(type, key->name, FALSE); if (ad != NULL)
{ // Adding the index into the drop list for replacing
alter_info->flags |= ALTER_DROP_INDEX;
alter_info->drop_list.push_back(ad, thd->mem_root);
}
}
}
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
partition_info *tab_part_info= table->part_info;
thd->work_part_info= thd->lex->part_info; if (tab_part_info)
{ /* ALTER TABLE ADD PARTITION IF NOT EXISTS */ if ((alter_info->partition_flags & ALTER_PARTITION_ADD) &&
thd->lex->create_info.if_not_exists())
{
partition_info *alt_part_info= thd->lex->part_info; if (alt_part_info)
{
List_iterator<partition_element> new_part_it(alt_part_info->partitions);
partition_element *pe; while ((pe= new_part_it++))
{ if (!tab_part_info->has_unique_name(pe))
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_SAME_NAME_PARTITION,
ER_THD(thd, ER_SAME_NAME_PARTITION),
pe->partition_name.str);
alter_info->partition_flags&= ~ALTER_PARTITION_ADD;
thd->work_part_info= NULL; break;
}
}
}
} /* ALTER TABLE DROP PARTITION IF EXISTS */ if ((alter_info->partition_flags & ALTER_PARTITION_DROP) &&
thd->lex->if_exists())
{
List_iterator<constchar> names_it(alter_info->partition_names); constchar *name;
while ((name= names_it++))
{
List_iterator<partition_element> part_it(tab_part_info->partitions);
partition_element *part_elem; while ((part_elem= part_it++))
{ if (part_elem->partition_name.streq(Lex_cstring_strlen(name))) break;
} if (!part_elem)
{
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_PARTITION_DOES_NOT_EXIST,
ER_THD(thd, ER_PARTITION_DOES_NOT_EXIST));
names_it.remove();
}
} if (alter_info->partition_names.elements == 0)
alter_info->partition_flags&= ~ALTER_PARTITION_DROP;
}
} #endif/*WITH_PARTITION_STORAGE_ENGINE*/
/* ADD CONSTRAINT IF NOT EXISTS. */
{
List_iterator<Virtual_column_info> it(alter_info->check_constraint_list);
Virtual_column_info *check;
TABLE_SHARE *share= table->s;
uint c;
while ((check=it++))
{ if (!check->if_not_exists && check->name.length) continue; for (c= share->field_check_constraints;
c < share->table_check_constraints ; c++)
{
Virtual_column_info *dup= table->check_constraints[c]; if (check->name.streq_safe(dup->name))
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_DUP_CONSTRAINT_NAME, ER_THD(thd, ER_DUP_CONSTRAINT_NAME), "CHECK", check->name.str);
it.remove(); if (alter_info->check_constraint_list.elements == 0)
alter_info->flags&= ~ALTER_ADD_CHECK_CONSTRAINT;
/* Gothroughfieldsinoldversionoftableanddetectchangestothem. Wedon'twanttorelysolelyonAlter_infoflagsforthissince: a)newdefinitionofcolumncanbefullyidenticaltotheoldone despitethefactthatthiscolumnismentionedinMODIFYclause. b)evenifnewcolumntypediffersfromitsoldcolumnfrommetadata pointofview,itmightbeidenticalfromstorageenginepoint ofview(e.g.whenENUM('a','b')ischangedtoENUM('a','b',c')). c)flagspassedtostorageenginecontainmoredetailedinformation aboutnatureofchangesthanthoseprovidedfromparser.
*/ bool maybe_alter_vcol= false;
uint field_stored_index= 0; for (f_ptr= table->field; (field= *f_ptr); f_ptr++,
field_stored_index+= field->stored_in_db())
{ /* Clear marker for renamed or dropped field
which we are going to set later. */
field->flags&= ~(FIELD_IS_RENAMED | FIELD_IS_DROPPED);
/* Use transformed info to evaluate flags for storage engine. */
uint new_field_index= 0, new_field_stored_index= 0;
new_field_it.init(alter_info->create_list); while ((new_field= new_field_it++))
{ if (new_field->field == field) break;
new_field_index++;
new_field_stored_index+= new_field->stored_in_db();
}
if (new_field)
{ /* Field is not dropped. Evaluate changes bitmap for it. */
if (!is_equal)
{ if (field->table->file->can_convert_nocopy(*field, *new_field))
{ /* Newcolumntypediffersfromtheoldone,butstorageenginecan changeitbyitself. (forexample,VARCHAR(300)ischangedtoVARCHAR(400)).
*/
ha_alter_info->handler_flags|= ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE;
} else
{ /* New column type is incompatible with old one. */
ha_alter_info->handler_flags|= field->stored_in_db()
? ALTER_STORED_COLUMN_TYPE
: ALTER_VIRTUAL_COLUMN_TYPE;
if (table->s->tmp_table == NO_TMP_TABLE)
{ if (alter_info->drop_stat_fields.push_back(field, thd->mem_root))
DBUG_RETURN(true);
KEY *key_info= table->key_info; for (uint i= 0; i < table->s->total_keys; i++, key_info++)
{ if (!field->part_of_key.is_set(i)) continue;
if (field->vcol_info->is_in_partitioning_expr() ||
field->flags & PART_KEY_FLAG || field->stored_in_db())
{ if (value_changes)
ha_alter_info->handler_flags|= ALTER_COLUMN_VCOL; else
maybe_alter_vcol= true;
}
} else/* base <-> stored */
ha_alter_info->handler_flags|= ALTER_STORED_COLUMN_TYPE;
}
/* Checkiffieldwasrenamed(case-sensitivefordetectingcasechange)
*/ if (cmp(&field->field_name, &new_field->field_name))
{
field->flags|= FIELD_IS_RENAMED;
ha_alter_info->handler_flags|= ALTER_COLUMN_NAME; if (alter_info->add_stat_rename_field(field,
&new_field->field_name,
thd->mem_root))
DBUG_RETURN(true);
}
/* Check that NULL behavior is same for old and new fields */ if ((new_field->flags & NOT_NULL_FLAG) !=
(uint) (field->flags & NOT_NULL_FLAG))
{ if (new_field->flags & NOT_NULL_FLAG)
ha_alter_info->handler_flags|= ALTER_COLUMN_NOT_NULLABLE; else
ha_alter_info->handler_flags|= ALTER_COLUMN_NULLABLE;
}
/* Detectchangesincolumnorder.
*/ if (field->stored_in_db())
{ if (field_stored_index != new_field_stored_index)
ha_alter_info->handler_flags|= ALTER_STORED_COLUMN_ORDER;
} else
{ if (field->field_index != new_field_index)
ha_alter_info->handler_flags|= ALTER_VIRTUAL_COLUMN_ORDER;
}
/* Detect changes in storage type of column */ if (new_field->field_storage_type() != field->field_storage_type())
ha_alter_info->handler_flags|= ALTER_COLUMN_STORAGE_TYPE;
/* Detect changes in column format of column */ if (new_field->column_format() != field->column_format())
ha_alter_info->handler_flags|= ALTER_COLUMN_COLUMN_FORMAT;
if (engine_options_differ(field->option_struct, new_field->option_struct,
table->file->ht->field_options))
{
ha_alter_info->handler_flags|= ALTER_COLUMN_OPTION;
ha_alter_info->create_info->fields_option_struct[f_ptr - table->field]=
new_field->option_struct;
}
} else
{ // Field is not present in new version of table and therefore was dropped.
field->flags|= FIELD_IS_DROPPED; if (field->stored_in_db())
ha_alter_info->handler_flags|= ALTER_DROP_STORED_COLUMN; else
ha_alter_info->handler_flags|= ALTER_DROP_VIRTUAL_COLUMN;
}
}
new_field_it.init(alter_info->create_list); while ((new_field= new_field_it++))
{ if (! new_field->field)
{ // Field is not present in old version of table and therefore was added. if (new_field->vcol_info)
{ if (new_field->stored_in_db())
ha_alter_info->handler_flags|= ALTER_ADD_STORED_GENERATED_COLUMN; else
ha_alter_info->handler_flags|= ALTER_ADD_VIRTUAL_COLUMN;
} else
ha_alter_info->handler_flags|= ALTER_ADD_STORED_BASE_COLUMN;
}
}
/* Stepthroughallkeysoftheoldtableandsearchmatchingnewkeys.
*/
ha_alter_info->index_drop_count= 0;
ha_alter_info->index_add_count= 0; for (table_key= table->key_info; table_key < table_key_end; table_key++)
{ /* Search a new key with the same name. */ for (new_key= ha_alter_info->key_info_buffer;
new_key < new_key_end;
new_key++)
{ if (!cmp(&table_key->name, &new_key->name)) break;
} if (new_key >= new_key_end)
{ /* Key not found. Add the key to the drop buffer. */
ha_alter_info->index_drop_buffer
[ha_alter_info->index_drop_count++]=
table_key;
DBUG_PRINT("info", ("index dropped: '%s'", table_key->name.str)); continue;
}
switch (compare_keys_but_name(table_key, new_key, alter_info, table, new_pk,
old_pk))
{ case Compare_keys::Equal: continue; case Compare_keys::EqualButKeyPartLength:
ha_alter_info->handler_flags|= ALTER_COLUMN_INDEX_LENGTH; continue; case Compare_keys::EqualButComment:
ha_alter_info->handler_flags|= ALTER_CHANGE_INDEX_COMMENT; continue; case Compare_keys::NotEqual: break;
}
/* Key modified. Add the key / key offset to both buffers. */
ha_alter_info->index_drop_buffer
[ha_alter_info->index_drop_count++]=
table_key;
ha_alter_info->index_add_buffer
[ha_alter_info->index_add_count++]=
(uint)(new_key - ha_alter_info->key_info_buffer); /* Mark all old fields which are used in newly created index. */
DBUG_PRINT("info", ("index changed: '%s'", table_key->name.str));
} /*end of for (; table_key < table_key_end;) */
/* Stepthroughallkeysofthenewtableandfindmatchingoldkeys.
*/ for (new_key= ha_alter_info->key_info_buffer;
new_key < new_key_end;
new_key++)
{ /* Search an old key with the same name. */ for (table_key= table->key_info; table_key < table_key_end; table_key++)
{ if (!cmp(&table_key->name, &new_key->name)) break;
} if (table_key >= table_key_end)
{ /* Key not found. Add the offset of the key to the add buffer. */
ha_alter_info->index_add_buffer
[ha_alter_info->index_add_count++]=
(uint)(new_key - ha_alter_info->key_info_buffer);
DBUG_PRINT("info", ("index added: '%s'", new_key->name.str));
} else
ha_alter_info->create_info->indexes_option_struct[table_key - table->key_info]=
new_key->option_struct;
}
for (uint i= 0; i < ha_alter_info->index_add_count; i++)
{
uint *add_buffer= ha_alter_info->index_add_buffer; const KEY *new_key= ha_alter_info->key_info_buffer + add_buffer[i];
/* Now let us calculate flags for storage engine API. */
/* Figure out what kind of indexes we are dropping. */
KEY **dropped_key;
KEY **dropped_key_end= ha_alter_info->index_drop_buffer +
ha_alter_info->index_drop_count;
for (dropped_key= ha_alter_info->index_drop_buffer;
dropped_key < dropped_key_end; dropped_key++)
{
table_key= *dropped_key;
if (table_key->flags & HA_NOSAME)
{ if (table_key == old_pk)
ha_alter_info->handler_flags|= ALTER_DROP_PK_INDEX; else
ha_alter_info->handler_flags|= ALTER_DROP_UNIQUE_INDEX;
} else
ha_alter_info->handler_flags|= ALTER_DROP_NON_UNIQUE_NON_PRIM_INDEX;
}
/* Now figure out what kind of indexes we are adding. */ for (uint add_key_idx= 0; add_key_idx < ha_alter_info->index_add_count; add_key_idx++)
{
new_key= ha_alter_info->key_info_buffer + ha_alter_info->index_add_buffer[add_key_idx];
if (new_key->flags & HA_NOSAME)
{ if (new_key == new_pk)
ha_alter_info->handler_flags|= ALTER_ADD_PK_INDEX; else
ha_alter_info->handler_flags|= ALTER_ADD_UNIQUE_INDEX;
} else
ha_alter_info->handler_flags|= ALTER_ADD_NON_UNIQUE_NON_PRIM_INDEX; /* Adding high-level index is algorithm=copy operation. */ if (new_key->algorithm == HA_KEY_ALG_VECTOR)
ha_alter_info->inplace_supported= HA_ALTER_INPLACE_NOT_SUPPORTED;
}
/* Create the prepared information. */ int create_table_mode= table->s->tmp_table == NO_TMP_TABLE ?
C_ORDINARY_CREATE : C_ALTER_TABLE; if (mysql_prepare_create_table(thd, create_info, &tmp_alter_info,
&db_options, table->file, &key_info_buffer,
&key_count, create_table_mode))
DBUG_RETURN(1);
/* Some very basic checks. */
uint fields= table->s->fields;
/* There is no field count on fully-invisible fields, count them. */ for (Field **f_ptr= table->field; *f_ptr; f_ptr++)
{ if ((*f_ptr)->invisible >= INVISIBLE_FULL)
fields--;
}
/* Go through fields and check if they are compatible. */
tmp_new_field_it.init(tmp_alter_info.create_list); for (Field **f_ptr= table->field; *f_ptr; f_ptr++)
{
Field *field= *f_ptr; /* Skip hidden generated field like long hash index. */ if (field->invisible >= INVISIBLE_SYSTEM) continue;
Create_field *tmp_new_field= tmp_new_field_it++;
/* Check that NULL behavior is the same. */ if ((tmp_new_field->flags & NOT_NULL_FLAG) !=
(uint) (field->flags & NOT_NULL_FLAG))
DBUG_RETURN(false);
if (field->vcol_info)
{ if (!tmp_new_field->field->vcol_info)
DBUG_RETURN(false); if (!field->vcol_info->is_equal(tmp_new_field->field->vcol_info, true))
DBUG_RETURN(false);
}
/* Check if field was renamed */ if (!field->field_name.streq(tmp_new_field->field_name))
DBUG_RETURN(false);
/* Evaluate changes bitmap and send to check_if_incompatible_data() */
uint field_changes= field->is_equal(*tmp_new_field); if (field_changes != IS_EQUAL_YES)
DBUG_RETURN(false);
changes|= field_changes;
}
/* Check if changes are compatible with current handler. */ if (table->file->check_if_incompatible_data(create_info, changes))
DBUG_RETURN(false);
/* Go through keys and check if they are compatible. */
KEY *table_key= table->s->key_info;
KEY *table_key_end= table_key + table->s->keys;
KEY *new_key;
KEY *new_key_end= key_info_buffer + key_count;
/* Step through all keys of the first table and search matching keys. */ for (; table_key < table_key_end; table_key++)
{ /* Search a key with the same name. */ for (new_key= key_info_buffer; new_key < new_key_end; new_key++)
{ if (!cmp(&table_key->name, &new_key->name)) break;
} if (new_key >= new_key_end)
DBUG_RETURN(false);
/* Check that the key types are compatible. */ if ((table_key->algorithm != new_key->algorithm) ||
((table_key->flags & HA_KEYFLAG_MASK) !=
(new_key->flags & HA_KEYFLAG_MASK)) ||
(table_key->user_defined_key_parts !=
new_key->user_defined_key_parts))
DBUG_RETURN(false);
/* Step through all keys of the second table and find matching keys. */ for (new_key= key_info_buffer; new_key < new_key_end; new_key++)
{ /* Search a key with the same name. */ for (table_key= table->s->key_info; table_key < table_key_end; table_key++)
{ if (!cmp(&table_key->name, &new_key->name)) break;
} if (table_key >= table_key_end)
DBUG_RETURN(false);
}
*metadata_equal= true; // Tables are compatible
DBUG_RETURN(false);
}
returntrue; // not really an error to be handled by caller specifically
}
mysql_mutex_unlock(&mi->start_alter_lock); /* Wehavetocallwaitformasterherebecauseinmaincalculation wecanerroroutbeforecallingwaitformaster (forexampleifcopy_data_between_tablesfails)
*/ if (info->state == start_alter_state::REGISTERED)
wait_for_master(thd); if(process_master_state(thd, 1, start_alter_id, if_exists)) returntrue;
} else #endif if (partial_alter) // Write only if SA written
{ // Send the rollback message
Write_log_with_flags wlwf(thd, Gtid_log_event::FL_ROLLBACK_ALTER_E1); if(write_bin_log_with_if_exists(thd, false, false, if_exists, false)) returntrue;
partial_alter= false;
} returnfalse;
}
// It's now safe to take the table level lock. if (lock_tables(thd, table_list, alter_ctx->tables_opened, 0)) goto cleanup;
DEBUG_SYNC(thd, "alter_table_inplace_after_lock_upgrade");
THD_STAGE_INFO(thd, stage_alter_inplace_prepare);
switch (inplace_supported) { case HA_ALTER_ERROR: case HA_ALTER_INPLACE_NOT_SUPPORTED:
DBUG_ASSERT(0); // fall through case HA_ALTER_INPLACE_NO_LOCK: case HA_ALTER_INPLACE_INSTANT: case HA_ALTER_INPLACE_COPY_NO_LOCK: case HA_ALTER_INPLACE_NOCOPY_NO_LOCK: switch (alter_info->requested_lock) { case Alter_info::ALTER_TABLE_LOCK_DEFAULT: case Alter_info::ALTER_TABLE_LOCK_NONE:
ha_alter_info->online= true; break; case Alter_info::ALTER_TABLE_LOCK_SHARED: case Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE: break;
} break; case HA_ALTER_INPLACE_EXCLUSIVE_LOCK: case HA_ALTER_INPLACE_SHARED_LOCK: case HA_ALTER_INPLACE_COPY_LOCK: case HA_ALTER_INPLACE_NOCOPY_LOCK: break;
}
/* We can abort alter table for any table type */
thd->abort_on_warning= !ha_alter_info->ignore && thd->is_strict_mode();
res= table->file->ha_inplace_alter_table(altered_table, ha_alter_info);
thd->abort_on_warning= false;
if (res || (start_alter_id && wait_for_master(thd))) goto rollback_no_restore_lock;
DEBUG_SYNC(thd, "alter_table_inplace_before_lock_upgrade"); // Upgrade to EXCLUSIVE before commit. if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME)) goto rollback_no_restore_lock;
/* Set MDL_BACKUP_DDL */ if (backup_reset_alter_copy_lock(thd)) goto rollback_no_restore_lock;
/* Crashing here should cause the original table to be used */
debug_crash_here("ddl_log_alter_after_copy"); /* Ifwearekilledafterthispoint,weshouldignoreandcontinue. Wehavemostlycompletedtheoperationatthispoint,thereshould benolongwaitsleft.
*/
/* Replacetheold.FRMwiththenew.FRM,butkeeptheoldnamefornow. Renametothenewname(ifneeded)willbehandledseparatelybelow.
*/ /* TODO:removethischeckofthd->is_error()(nowitintercept errorsinsomeval_*()methodsandbringsomesingleplaceto sucherrorinterception).
*/ if (mysql_rename_table(db_type, &alter_ctx->new_db, &alter_ctx->tmp_name,
&alter_ctx->db, &alter_ctx->alias,
&alter_ctx->tmp_id,
QRMT_FRM | QRMT_PAR | FN_FROM_IS_TMP) ||
thd->is_error())
{ // Since changes were done in-place, we can't revert them. goto err;
}
debug_crash_here("ddl_log_alter_after_rename_frm");
// Rename altered table in case of ALTER TABLE ... RENAME if (alter_ctx->is_table_renamed())
{
DBUG_ASSERT(!tdc_share_is_cached(thd, alter_ctx->db.str,
alter_ctx->table_name.str)); if (mysql_rename_table(db_type, &alter_ctx->db, &alter_ctx->table_name,
&alter_ctx->new_db, &alter_ctx->new_alias,
&alter_ctx->tmp_id, QRMT_DEFAULT))
{ /* Iftherenamefailswewillstillhaveaworkingtable withtheoldname,butwithotherchangesapplied.
*/ goto err;
}
debug_crash_here("ddl_log_alter_before_rename_triggers"); if (Table_triggers_list::change_table_name(thd, trigger_param,
&alter_ctx->db,
&alter_ctx->alias,
&alter_ctx->table_name,
&alter_ctx->new_db,
&alter_ctx->new_alias))
{ /* Iftherenameoftriggerfilesfails,trytorenamethetable backsoweatleasthavematchingtableandtriggerfiles.
*/
(void) mysql_rename_table(db_type,
&alter_ctx->new_db, &alter_ctx->new_alias,
&alter_ctx->db, &alter_ctx->alias,
&alter_ctx->id,
QRMT_DEFAULT | NO_FK_CHECKS);
ddl_log_disable_entry(ddl_log_state);
DBUG_RETURN(true);
}
rename_table_in_stat_tables(thd, &alter_ctx->db, &alter_ctx->alias,
&alter_ctx->new_db, &alter_ctx->new_alias);
debug_crash_here("ddl_log_alter_after_rename_triggers");
}
DBUG_RETURN(commit_succeded_with_error);
rollback_restore_lock: /* Wait for backup if it is running */
backup_reset_alter_copy_lock(thd);
rollback_no_restore_lock:
table->file->ha_commit_inplace_alter_table(altered_table,
ha_alter_info, false);
cleanup: if (reopen_tables)
{ /* Close the only table instance which is still around. */
close_all_tables_for_name(thd, table->s,
alter_ctx->is_table_renamed() ?
HA_EXTRA_PREPARE_FOR_RENAME :
HA_EXTRA_NOT_USED,
NULL); if (thd->locked_tables_list.reopen_tables(thd, false))
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
}
err:
DBUG_RETURN(true);
}
/** maximumpossiblelengthforcertainblobtypes.
@param[in]typeBlobtype(e.g.MYSQL_TYPE_TINY_BLOB)
@return length
*/
static uint
blob_length_by_type(enum_field_types type)
{ switch (type)
{ case MYSQL_TYPE_TINY_BLOB: return255; case MYSQL_TYPE_BLOB: return65535; case MYSQL_TYPE_MEDIUM_BLOB: return16777215; case MYSQL_TYPE_LONG_BLOB: return (uint) UINT_MAX32; default:
DBUG_ASSERT(0); // we should never go here return0;
}
}
staticinline void append_drop_column(THD *thd, String *str, Field *field)
{ if (str->length())
str->append(STRING_WITH_LEN(", "));
str->append(STRING_WITH_LEN("DROP COLUMN "));
append_identifier(thd, str, &field->field_name);
}
create_info->varchar= FALSE; /* Let new create options override the old ones */ if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
create_info->min_rows= table->s->min_rows; if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
create_info->max_rows= table->s->max_rows; if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
create_info->avg_row_length= table->s->avg_row_length;
if (create_info->resolve_to_charset_collation_context(thd,
thd->charset_collation_context_alter_table(table->s)))
DBUG_RETURN(true);
if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
{ /* Table has an autoincrement, copy value to new table */
table->file->info(HA_STATUS_AUTO);
create_info->auto_increment_value= table->file->stats.auto_increment_value;
}
if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
create_info->key_block_size= table->s->key_block_size;
if (!(used_fields & HA_CREATE_USED_STATS_SAMPLE_PAGES))
create_info->stats_sample_pages= table->s->stats_sample_pages;
if (!(used_fields & HA_CREATE_USED_STATS_AUTO_RECALC))
create_info->stats_auto_recalc= table->s->stats_auto_recalc;
if (!(used_fields & HA_CREATE_USED_TRANSACTIONAL))
create_info->transactional= table->s->transactional;
if (!(used_fields & HA_CREATE_USED_SEQUENCE))
create_info->sequence= table->s->table_type == TABLE_TYPE_SEQUENCE;
column_rename_param.db_name= table->s->db;
column_rename_param.table_name= table->s->table_name; if (column_rename_param.fields.copy(&alter_info->create_list, root))
DBUG_RETURN(1); // OOM
restore_record(table, s->default_values); // Empty record for DEFAULT
if (merge_engine_options(table->s->option_list, create_info->option_list,
&create_info->option_list, root))
DBUG_RETURN(1);
table->file->get_foreign_key_list(thd, &fk_list);
/* Firstcollectallfieldsfromtablewhichisn'tindrop_list
*/
bitmap_clear_all(&table->tmp_set); for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
{ if (field->invisible == INVISIBLE_FULL) continue;
Alter_drop *drop; if (field->type() == MYSQL_TYPE_VARCHAR)
create_info->varchar= TRUE; /* Check if field should be dropped */
drop_it.rewind(); while ((drop=drop_it++))
{ if (drop->type == Alter_drop::COLUMN &&
field->field_name.streq(drop->name)) break;
} /* DROPCOLUMNxxx 1.itdoesnotseeINVISIBLE_SYSTEMcolumns 2.otherwise,normallyacolumnisdropped 3.unlessit'sasystemversioningcolumn(butseebelow).
*/ if (drop && field->invisible < INVISIBLE_SYSTEM &&
!(field->flags & VERS_SYSTEM_FIELD &&
!(alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING)))
{ /* Reset auto_increment value if it was dropped */ if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
!(used_fields & HA_CREATE_USED_AUTO))
{
create_info->auto_increment_value=0;
create_info->used_fields|=HA_CREATE_USED_AUTO;
} if (table->s->tmp_table == NO_TMP_TABLE)
{ if (alter_info->drop_stat_fields.push_back(field, root))
DBUG_RETURN(true);
}
dropped_sys_vers_fields|= field->flags;
drop_it.remove();
dropped_fields= &table->tmp_set;
bitmap_set_bit(dropped_fields, field->field_index); continue;
} if (field->invisible == INVISIBLE_SYSTEM &&
field->flags & VERS_SYSTEM_FIELD)
{
vers_system_invisible= true;
} /* invisibleversioningcolumnisdroppedautomaticallyon DROPSYSTEMVERSIONING
*/ if (!drop && field->invisible >= INVISIBLE_SYSTEM &&
field->flags & VERS_SYSTEM_FIELD &&
alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING)
{ if (table->s->tmp_table == NO_TMP_TABLE)
{ if (alter_info->drop_stat_fields.push_back(field, root))
DBUG_RETURN(true);
} continue;
}
/* Check if field is changed */
def_it.rewind(); while ((def=def_it++))
{ if (def->change.str && field->field_name.streq(def->change)) break;
} if (def && field->invisible < INVISIBLE_SYSTEM)
{ // Field is changed
def->field=field; /* Addcolumnbeingupdatedtothelistofnewcolumns. NotethatcolumnswithAFTERclausesareaddedtotheend ofthelistfornow.Theirpositionswillbecorrectedlater.
*/
new_create_list.push_back(def, root); if (field->stored_in_db() != def->stored_in_db())
{
my_error(ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN, MYF(0)); goto err;
} if (!def->after.str)
{ /* IfthisALTERTABLEdoesn'thaveanAFTERclauseforthemodified columnthenremovethiscolumnfromthelistofcolumnstobe processed.Solaterwecaniterateoverthecolumnsremaining inthislistandprocessmodifiedcolumnswithAFTERclauseor addnewcolumns.
*/
def_it.remove();
}
} elseif (alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING &&
field->flags & VERS_SYSTEM_FIELD &&
field->invisible < INVISIBLE_SYSTEM)
{
StringBuffer<NAME_LEN*3> tmp;
append_drop_column(thd, &tmp, field);
my_error(ER_MISSING, MYF(0), table->s->table_name.str, tmp.c_ptr_safe()); goto err;
} elseif (drop && field->invisible < INVISIBLE_SYSTEM &&
field->flags & VERS_SYSTEM_FIELD &&
!(alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING))
{ /* "dropping" a versioning field only hides it from the user */
def= new (root) Create_field(thd, field, field);
def->invisible= INVISIBLE_SYSTEM;
alter_info->flags|= ALTER_CHANGE_COLUMN; if (field->flags & VERS_ROW_START)
create_info->vers_info.period.start=
create_info->vers_info.as_row.start=
def->field_name= Vers_parse_info::default_start;
else
create_info->vers_info.period.end=
create_info->vers_info.as_row.end=
def->field_name= Vers_parse_info::default_end;
new_create_list.push_back(def, root);
dropped_sys_vers_fields|= field->flags;
drop_it.remove();
} elseif (field->invisible < INVISIBLE_SYSTEM ||
(alter_info->flags & ALTER_VERS_EXPLICIT))
{ /* Thisfieldwasnotdroppedandnotchanged,addittothelist forthenewtable.
*/
def= new (root) Create_field(thd, field, field);
new_create_list.push_back(def, root);
alter_it.rewind(); // Change default if ALTER
Alter_column *alter; while ((alter=alter_it++))
{ if (field->field_name.streq(alter->name)) break;
} if (alter)
{ if (alter->is_rename())
{
def->change= Lex_ident_column(alter->name);
def->field_name= Lex_ident_column(alter->new_name); if (vers_system_invisible)
def->invisible= VISIBLE;
column_rename_param.fields.push_back(def); if (field->flags & VERS_ROW_START)
{
create_info->vers_info.as_row.start= Lex_ident_column(alter->new_name);
create_info->vers_info.period.start= Lex_ident_column(alter->new_name);
} elseif (field->flags & VERS_ROW_END)
{
create_info->vers_info.as_row.end= Lex_ident_column(alter->new_name);
create_info->vers_info.period.end= Lex_ident_column(alter->new_name);
} if (table->s->period.name)
{ if (field == table->period_start_field())
period_start_name= Lex_ident_column(alter->new_name); elseif (field == table->period_end_field())
period_end_name= Lex_ident_column(alter->new_name);
}
} else
{ if (def->default_value != alter->default_value &&
def->has_default_now_unireg_check())
def->unireg_check= Field::NONE; if ((def->default_value= alter->default_value) ||
!(def->flags & NOT_NULL_FLAG))
def->flags&= ~NO_DEFAULT_VALUE_FLAG; else
def->flags|= NO_DEFAULT_VALUE_FLAG;
}
alter_it.remove();
}
} else
{
DBUG_ASSERT(field->invisible == INVISIBLE_SYSTEM);
def= new (root) Create_field(thd, field, field);
new_create_tail.push_back(def, root);
}
}
/* Ifwearedoingarenameofacolumn,updateallreferencesinvirtual columnexpressions,constraintsanddefaultstousethenewcolumnname
*/ if (alter_info->flags & ALTER_RENAME_COLUMN)
{
alter_it.rewind();
Alter_column *alter; while ((alter=alter_it++))
{ if (alter->is_rename())
{
my_error(ER_BAD_FIELD_ERROR, MYF(0), alter->name.str,
table->s->table_name.str); goto err;
}
} for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
{ if (field->vcol_info)
field->vcol_info->expr->walk(&Item::rename_fields_processor,
&column_rename_param, WALK_SUBQUERY); if (field->check_constraint)
field->check_constraint->expr->walk(&Item::rename_fields_processor,
&column_rename_param,
WALK_SUBQUERY); if (field->default_value)
field->default_value->expr->walk(&Item::rename_fields_processor,
&column_rename_param, WALK_SUBQUERY);
} #ifdef WITH_PARTITION_STORAGE_ENGINE if (thd->work_part_info)
{
partition_info *part_info= thd->work_part_info;
List_iterator<Create_field> def_it(column_rename_param.fields); constbool part_field_list= !part_info->part_field_list.is_empty(); constbool subpart_field_list= !part_info->subpart_field_list.is_empty(); if (part_info->part_expr)
part_info->part_expr->walk(&Item::rename_fields_processor,
&column_rename_param, WALK_SUBQUERY); if (part_info->subpart_expr)
part_info->subpart_expr->walk(&Item::rename_fields_processor,
&column_rename_param, WALK_SUBQUERY); if (part_field_list || subpart_field_list)
{ while (Create_field *def= def_it++)
{ if (def->change.str)
{ if (part_field_list)
rename_field_in_list(def, &part_info->part_field_list); if (subpart_field_list)
rename_field_in_list(def, &part_info->subpart_field_list);
} /* if (def->change.str) */
} /* while (def) */
} /* if (part_field_list || subpart_field_list) */ // Force reopen because new column name is on root
table->mark_table_for_reopen();
} /* if (part_info) */ #endif // Force reopen because new column name is on root
table->mark_table_for_reopen();
}
Alter_index_ignorability *index_ignorability; while((index_ignorability= ignorability_index_it++))
{ if (key_name.streq(index_ignorability->name()))
ignorability_index_it.remove();
}
/* If this index is to stay in the table check if it has to be renamed. */
List_iterator<Alter_rename_key> rename_key_it(rename_key_list);
Alter_rename_key *rename_key;
while ((rename_key= rename_key_it++))
{ if (key_name.streq(rename_key->old_name))
{ if (key_name.streq(primary_key_name))
{
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), rename_key->old_name.str); goto err;
} elseif (rename_key->new_name.streq(primary_key_name))
{
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), rename_key->new_name.str); goto err;
}
key_name= rename_key->new_name; // New name of current key_info if (cmp(&rename_key->old_name, &rename_key->new_name))
{ /* Key was renamed */
alter_info->add_stat_rename_index(key_info, &rename_key->new_name, root);
}
rename_key_it.remove();
if (key_info->algorithm == HA_KEY_ALG_LONG_HASH)
{
setup_keyinfo_hash(key_info);
long_hash_key= true;
} constchar *dropped_key_part= NULL; bool user_keyparts= false; // some user-defined keyparts left
KEY_PART_INFO *key_part= key_info->key_part;
key_parts.empty();
uint key_parts_nr= key_info->user_defined_key_parts; if (key_info->without_overlaps)
key_parts_nr-= 2;
bool delete_index_stat= FALSE; for (uint j=0 ; j < key_parts_nr ; j++,key_part++)
{
Field *kfield= key_part->field; if (!kfield) continue; // Wrong field (from UNIREG) const Lex_ident_column key_part_name(kfield->field_name);
Create_field *cfield;
uint key_part_length;
field_it.rewind(); while ((cfield=field_it++))
{ if (cfield->change.str)
{ if (cfield->change.streq(key_part_name)) break;
} elseif (cfield->field_name.streq(key_part_name)) break;
} if (!cfield)
{ if (primary_key)
alter_ctx->modified_primary_key= true;
delete_index_stat= TRUE; if (!(kfield->flags & VERS_SYSTEM_FIELD))
dropped_key_part= key_part_name.str; continue; // Field is removed
}
key_part_length= key_part->length; if (cfield->field) // Not new field
{ /* Ifthefieldcan'thaveonlyapartusedinakeyaccordingtoits newtype,orshouldnotbeusedpartiallyaccordingtoits previoustype,orthefieldlengthislessthanthekeypart length,unsetthekeypartlength.
if (keep)
{
Item *expr_copy= check->expr->shallow_copy_with_checks(thd);
check= new Virtual_column_info();
check->name= share->period.constr_name;
check->automatic_name= true;
check->expr= expr_copy;
create_info->period_info.constr= check;
}
} /* see if the constraint depends on *only* on dropped fields */ if (keep && dropped_fields)
{
table->default_column_bitmaps();
bitmap_clear_all(table->read_set);
check->expr->walk(&Item::register_field_in_read_map, 0, WALK_SUBQUERY); if (bitmap_is_subset(table->read_set, dropped_fields))
keep= false; elseif (bitmap_is_overlapping(dropped_fields, table->read_set))
{
bitmap_intersect(table->read_set, dropped_fields);
uint field_nr= bitmap_get_first_set(table->read_set);
my_error(ER_BAD_FIELD_ERROR, MYF(0),
table->field[field_nr]->field_name.str, "CHECK"); goto err;
}
} if (keep)
{ if (alter_info->flags & ALTER_RENAME_COLUMN)
{
check->expr->walk(&Item::rename_fields_processor,
&column_rename_param, WALK_SUBQUERY); // Force reopen because new column name is on root
table->mark_table_for_reopen();
}
new_constraint_list.push_back(check, root);
}
}
}
if (!alter_info->check_constraint_list.is_empty())
{ /* Check the table FOREIGN KEYs for name duplications. */
FOREIGN_KEY_INFO *f_key;
List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_list); while ((f_key= fk_key_it++))
{
List_iterator_fast<Virtual_column_info>
c_it(alter_info->check_constraint_list);
Virtual_column_info *check; while ((check= c_it++))
{ if (!check->name.length || check->automatic_name) continue;
/* Add new constraints */
new_constraint_list.append(&alter_info->check_constraint_list);
if (alter_info->drop_list.elements)
{
Alter_drop *drop;
drop_it.rewind();
List<LEX_CSTRING> dropped_fk; while ((drop=drop_it++)) { switch (drop->type) { case Alter_drop::KEY: case Alter_drop::COLUMN: case Alter_drop::CHECK_CONSTRAINT: case Alter_drop::PERIOD:
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), drop->type_name(),
drop->name.str); goto err; case Alter_drop::FOREIGN_KEY: // Leave the DROP FOREIGN KEY names in the alter_info->drop_list. /* If this is DROP FOREIGN KEY without IF EXIST,
we can now check does it exists and if not report a error. */ if (!drop->drop_if_exists)
{
List <FOREIGN_KEY_INFO> fk_child_key_list;
table->file->get_foreign_key_list(thd, &fk_child_key_list); if (fk_child_key_list.is_empty())
{
fk_not_found:
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), drop->type_name(),
drop->name.str); goto err;
}
List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_child_key_list); while (FOREIGN_KEY_INFO *f_key= fk_key_it++)
{ if (Lex_ident_column(*f_key->foreign_id).streq(drop->name))
{
List_iterator<LEX_CSTRING> check_it(dropped_fk); while (LEX_CSTRING *dropped_name = check_it++) if (Lex_ident_column(*f_key->foreign_id).streq(*dropped_name)) goto fk_not_found;
dropped_fk.push_back(f_key->foreign_id); goto fk_found;
}
} goto fk_not_found;
fk_found: break;
} break;
}
}
}
if (rename_key_list.elements)
{
my_error(ER_KEY_DOES_NOT_EXISTS, MYF(0), rename_key_list.head()->old_name.str,
table->s->table_name.str); goto err;
}
if (alter_index_ignorability_list.elements)
{
my_error(ER_KEY_DOES_NOT_EXISTS, MYF(0),
alter_index_ignorability_list.head()->name().str,
table->s->table_name.str); goto err;
}
if (!create_info->comment.str)
{
create_info->comment.str= table->s->comment.str;
create_info->comment.length= table->s->comment.length;
}
if (info->state == start_alter_state::INVALID)
{ /* the caller has not yet called SA logging nor wait for master decision */ if (!write_bin_log_start_alter(thd, partial_alter, start_alter_id,
if_exists))
wait_for_master(thd);
DBUG_ASSERT(!partial_alter);
}
/* this function shouldn't be called twice */
DBUG_ASSERT(start_alter_id);
// Exit earlier when possible if (thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO) returntrue; if ((alter_info->flags | ALTER_CHANGE_COLUMN) != alter_info->flags) returntrue;
/* Findatleastoneuniqueindex(withoutNULLs),allcolumnsofwhich remaininthetableunchangedtopresumeit'sasafeALTERTABLE.
*/ for (uint k= 0; k < table->s->keys; k++)
{ const KEY &key= table->key_info[k]; if ((key.flags & HA_NOSAME) == 0 || key.flags & HA_NULL_PART_KEY) continue; bool key_parts_good= true; for (uint kp= 0; kp < key.user_defined_key_parts && key_parts_good; kp++)
{ const Field *f= key.key_part[kp].field; // tmp_set contains dropped fields after mysql_prepare_alter_table
key_parts_good= !bitmap_is_set(&table->tmp_set, f->field_index);
if (key_parts_good) for (constauto &c: alter_info->create_list) if (c.field == f)
{
key_parts_good= f->is_equal(c); break;
}
} if (key_parts_good) returntrue;
}
for (constauto &c: alter_info->create_list)
{ if (c.flags & AUTO_INCREMENT_FLAG)
{ if (c.field && !(c.field->flags & AUTO_INCREMENT_FLAG)) returnfalse; break;
}
} returntrue;
}
*online= thd->locked_tables_mode != LTM_LOCK_TABLES && !table->s->tmp_table; if (!*online) return NULL;
*online= (new_table->file->ha_table_flags() & HA_NO_ONLINE_ALTER) == 0; if (!*online) return new_table->file->engine_name()->str;
*online= table->s->sequence == NULL; if (!*online) return"SEQUENCE";
*online= (alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING) == 0; if (!*online) return"DROP SYSTEM VERSIONING";
*online= !thd->lex->ignore; if (!*online) return"ALTER IGNORE TABLE";
*online= !table->versioned(VERS_TRX_ID); if (!*online) return"BIGINT GENERATED ALWAYS AS ROW_START";
List<FOREIGN_KEY_INFO> fk_list;
table->file->get_foreign_key_list(thd, &fk_list); for (auto &fk: fk_list)
{ if (fk_modifies_child(fk.delete_method) ||
fk_modifies_child(fk.update_method))
{
*online= false; // Don't fall to a common unsupported case to avoid heavy string ops. if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE)
{ return fk_modifies_child(fk.delete_method)
? thd->strcat({STRING_WITH_LEN("ON DELETE ")},
*fk_option_name(fk.delete_method)).str
: thd->strcat({STRING_WITH_LEN("ON UPDATE ")},
*fk_option_name(fk.update_method)).str;
} return NULL;
}
}
for (auto &c: alter_info->create_list)
{
*online= c.field || !(c.flags & AUTO_INCREMENT_FLAG); if (!*online) return"ADD COLUMN ... AUTO_INCREMENT";
auto *def= c.default_value;
*online= !(def && def->flags & VCOL_NEXTVAL // either it's a new field, or a NULL -> NOT NULL change
&& (!c.field || (!(c.field->flags & NOT_NULL_FLAG)
&& (c.flags & NOT_NULL_FLAG)))); if (!*online)
{ if (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_NONE) return NULL; // Avoid heavy string op constchar *fmt= ER_THD(thd, ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED);
LEX_CSTRING dflt{STRING_WITH_LEN("DEFAULT")};
LEX_CSTRING nxvl{STRING_WITH_LEN("NEXTVAL()")};
size_t len= strlen(fmt) + nxvl.length + c.field_name.length + dflt.length; char *resp= thd->alloc(len); // expression %s cannot be used in the %s clause of %sQ
my_snprintf(resp, len, fmt, nxvl.str, dflt.str, c.field_name.str); return resp;
}
}
*online= online_alter_check_autoinc(thd, alter_info, table); if (!*online) return"CHANGE COLUMN ... AUTO_INCREMENT";
if (table_kind)
{ /* Disable alter of enabled log tables */ if (logger.is_log_table_enabled(table_kind))
{
my_error(ER_BAD_LOG_STATEMENT, MYF(0), "ALTER");
DBUG_RETURN(true);
}
/* Disable alter of log tables to unsupported engine */ if ((used_engine) &&
(!create_info->db_type || /* unknown engine */
create_info->check_if_valid_log_table()))
DBUG_RETURN(true);
/* Temporary name for backup of original table */
backup_name.str= backup_name_buff;
backup_name.length= my_snprintf(backup_name_buff, sizeof(backup_name_buff)-1, "%s-backup-%lx-%llx", tmp_file_prefix,
current_pid, thd->thread_id);
/* Check if the new table type is a shared table */ if (ha_check_if_updates_are_ignored(thd, create_info->db_type, "ALTER"))
{ /* Removeoldlocal.frmfileifitexists.Weshouldusethenew sharedoneinthefuture.Thedropisnotlogged,theALTERtableis logged.
*/
table_list->mdl_request.type= MDL_EXCLUSIVE; /* This will only drop the .frm file and local tables, not shared ones */
error= mysql_rm_table(thd, table_list, 1, 0, 0, 1);
DBUG_RETURN(log_and_ok(thd));
}
// If alter used ENGINE= we use that if (create_info->used_fields & HA_CREATE_USED_ENGINE)
ht= create_info->db_type; // For partitioned tables resolve underlying handlerton elseif (table->file->partition_ht())
ht= table->file->partition_ht();
if (!wsrep_should_replicate_ddl(thd, ht))
DBUG_RETURN(true);
} #endif
DEBUG_SYNC(thd, "alter_table_after_open_tables");
if (table->versioned())
{ if (handlerton *hton1= create_info->db_type)
{
handlerton *hton2= table->file->partition_ht(); if (hton1 != hton2 &&
(ha_check_storage_engine_flag(hton1, HTON_NATIVE_SYS_VERSIONING) ||
ha_check_storage_engine_flag(hton2, HTON_NATIVE_SYS_VERSIONING)))
{
my_error(ER_VERS_ALTER_ENGINE_PROHIBITED, MYF(0), table_list->db.str,
table_list->table_name.str);
DBUG_RETURN(true);
}
} if (alter_info->vers_prohibited(thd))
{
my_error(ER_VERS_ALTER_NOT_ALLOWED, MYF(0),
table_list->db.str, table_list->table_name.str);
DBUG_RETURN(true);
}
}
/* Check that we are not trying to rename to an existing table */ if (alter_ctx.is_table_renamed())
{ if (table->s->tmp_table != NO_TMP_TABLE)
{ /* Checkwhetheratemporarytableexistswithsamerequestednewname. Ifsuchtableexists,theremustbeacorrespondingTABLE_SHAREin THD::all_temp_tableslist.
*/ if (thd->find_tmp_table_share(alter_ctx.new_db, alter_ctx.new_name))
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alter_ctx.new_alias.str);
DBUG_RETURN(true);
}
} else
{
MDL_request_list mdl_requests;
MDL_request target_db_mdl_request;
/* IfthisisanALTERTABLEandnoexplicitrowtypespecifiedreuse thetable'srowtype. Note:thisisthesameasiftherowtypewasspecifiedexplicitly.
*/ if (create_info->row_type == ROW_TYPE_NOT_USED)
{ /* ALTER TABLE without explicit row type */
create_info->row_type= table->s->row_type;
} else
{ /* ALTER TABLE with specific row type */
create_info->used_fields |= HA_CREATE_USED_ROW_FORMAT;
}
DBUG_PRINT("info", ("old type: %s new type: %s",
ha_resolve_storage_engine_name(old_db_type),
ha_resolve_storage_engine_name(new_db_type))); if (ha_check_storage_engine_flag(old_db_type, HTON_ALTER_NOT_SUPPORTED))
{
DBUG_PRINT("info", ("doesn't support alter"));
my_error(ER_ILLEGAL_HA, MYF(0), hton_name(old_db_type)->str,
alter_ctx.db.str, alter_ctx.table_name.str);
DBUG_RETURN(true);
}
if (ha_check_storage_engine_flag(new_db_type, HTON_ALTER_NOT_SUPPORTED))
{
DBUG_PRINT("info", ("doesn't support alter"));
my_error(ER_ILLEGAL_HA, MYF(0), hton_name(new_db_type)->str,
alter_ctx.new_db.str, alter_ctx.new_name.str);
DBUG_RETURN(true);
}
if (table->s->tmp_table == NO_TMP_TABLE)
mysql_audit_alter_table(thd, table_list); elseif (table_creation_was_logged && mysql_bin_log.is_open())
{ /* Protect against MDL error in binary logging */
DBUG_ASSERT(!mdl_ticket); if (!thd->mdl_context.MDL_ACQUIRE_LOCK(
MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
MDL_TRANSACTION, thd->variables.lock_wait_timeout))
DBUG_RETURN(true);
}
THD_STAGE_INFO(thd, stage_setup);
if (alter_info->flags & ALTER_DROP_CHECK_CONSTRAINT)
{ /* ALTERTABLEDROPCONSTRAINT shouldbereplacedwith...DROP[FOREIGN]KEY iftheconstraintistheFOREIGNKEYorUNIQUEone.
*/
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
Alter_drop *drop;
List <FOREIGN_KEY_INFO> fk_child_key_list;
table->file->get_foreign_key_list(thd, &fk_child_key_list);
alter_info->flags&= ~ALTER_DROP_CHECK_CONSTRAINT;
while ((drop= drop_it++))
{ if (drop->type == Alter_drop::CHECK_CONSTRAINT)
{
{ /* Test if there is a FOREIGN KEY with this name. */
FOREIGN_KEY_INFO *f_key;
List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_child_key_list);
while ((f_key= fk_key_it++))
{ if (Lex_ident_column(*f_key->foreign_id).streq(drop->name))
{
drop->type= Alter_drop::FOREIGN_KEY;
alter_info->flags|= ALTER_DROP_FOREIGN_KEY; goto do_continue;
}
}
}
{ /* Test if there is an UNIQUE with this name. */
uint n_key;
/* Check if rename of triggers are supported */ if (alter_ctx.is_table_renamed() &&
Table_triggers_list::prepare_for_rename(thd, &trigger_param,
alter_ctx.db,
Lex_ident_table(alter_ctx.alias),
alter_ctx.table_name,
alter_ctx.new_db,
Lex_ident_table(alter_ctx.new_alias)))
DBUG_RETURN(true);
/* We don't replicate alter table statement on temporary tables */ if (table_creation_was_logged)
{ if (write_bin_log_with_if_exists(thd, true, false, log_if_exists))
DBUG_RETURN(true);
}
DBUG_RETURN(false);
}
/* TestifweareonlydoingRENAMEorKEYSON/OFF.Thisworks aswearetestingifflags==0above.
*/ if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
alter_info->partition_flags == 0 &&
alter_info->algorithm(thd) !=
Alter_info::ALTER_TABLE_ALGORITHM_COPY) // No need to touch frm.
{ bool res;
if (!table->s->tmp_table)
{ // This requires X-lock, no other lock levels supported. if (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_DEFAULT &&
alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE)
{
my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0), "LOCK=NONE/SHARED", "LOCK=EXCLUSIVE");
DBUG_RETURN(true);
}
res= simple_rename_or_index_change(thd, table_list,
alter_info->keys_onoff,
&trigger_param,
&alter_ctx);
} else
{
res= simple_tmp_rename_or_index_change(thd, table_list,
alter_info->keys_onoff,
&alter_ctx);
}
DBUG_RETURN(res);
}
// In-place execution of ALTER TABLE for partitioning.
alter_info->db= alter_ctx.db;
alter_info->table_name= alter_ctx.table_name;
DBUG_RETURN(fast_alter_partition_table(thd, table, alter_info, &alter_ctx,
create_info, table_list));
} #endif
#ifdef WITH_WSREP // ALTER TABLE for sequence object, check can we support it if (table->s->sequence && WSREP(thd) &&
wsrep_check_sequence(thd, create_info->seq_create_info, used_engine))
DBUG_RETURN(TRUE); #endif/* WITH_WSREP */
/* ALTERTABLE...ENGINEtothesameengineisacommonwayto requesttablerebuild.SetALTER_RECREATEflagtoforcetable rebuild.
*/ if (new_db_type == old_db_type)
{ if (create_info->used_fields & HA_CREATE_USED_ENGINE)
alter_info->flags|= ALTER_RECREATE;
Ifrenameismadetoanotherdatabase: Createnewtablesinnewdatabase. Copydata. Removeoldtableandsymlinks.
*/ if (!alter_ctx.is_database_changed())
{ if (create_info->index_file_name)
{ /* Fix index_file_name to have 'tmp_name' as basename */
strmov(index_file, alter_ctx.tmp_name.str);
create_info->index_file_name=fn_same(index_file,
create_info->index_file_name, 1);
} if (create_info->data_file_name)
{ /* Fix data_file_name to have 'tmp_name' as basename */
strmov(data_file, alter_ctx.tmp_name.str);
create_info->data_file_name=fn_same(data_file,
create_info->data_file_name, 1);
}
} else
{ /* Ignore symlink if db is changed. */
create_info->data_file_name=create_info->index_file_name=0;
}
/* Create a new table version id for the new table */
my_uuid(uuid_buffer);
create_info->tabledef_version.str= uuid_buffer;
create_info->tabledef_version.length= MY_UUID_SIZE;
if (!table->s->tmp_table)
{
LEX_CSTRING path_to_frm= alter_ctx.get_tmp_cstring_path();
LEX_CSTRING tmp_table= backup_name; if (alter_ctx.is_table_renamed())
tmp_table= alter_ctx.new_alias;
// If SHARED lock and no particular algorithm was requested, use COPY. if (ha_alter_info.inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK &&
alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED &&
alter_info->algorithm(thd) == Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT)
use_inplace= false;
if (ha_alter_info.inplace_supported == HA_ALTER_INPLACE_NOT_SUPPORTED)
use_inplace= false;
alter_copy: /* ALTER TABLE using copy algorithm. */
/* Check if ALTER TABLE is compatible with foreign key definitions. */ if (fk_prepare_copy_alter_table(thd, table, alter_info, &alter_ctx)) goto err_new_table_cleanup;
if (!table->s->tmp_table)
{ // If EXCLUSIVE lock is requested, upgrade already. if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE &&
wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) goto err_new_table_cleanup;
DBUG_EXECUTE_IF("start_alter_delay_master", {
debug_sync_set_action(thd,
STRING_WITH_LEN("now wait_for alter_cont NO_CLEAR_EVENT"));
}); // It's now safe to take the table level lock. if (lock_tables(thd, table_list, alter_ctx.tables_opened,
MYSQL_LOCK_USE_MALLOC)) goto err_new_table_cleanup;
/* Mark that we have created table in storage engine. */
no_ha_table= false;
DEBUG_SYNC(thd, "alter_table_intermediate_table_created");
/* Open the table since we need to copy the data. */
new_table= thd->create_and_open_tmp_table(&frm, alter_ctx.get_tmp_path(),
alter_ctx.new_db,
alter_ctx.new_name, true); if (!new_table) goto err_new_table_cleanup;
DBUG_ASSERT(new_table->s->hlindexes() <= 1); for (uint i= new_table->s->keys; i < new_table->s->total_keys; i++) if (new_table->hlindex_open(i)) goto err_new_table_cleanup;
if (table->s->tmp_table != NO_TMP_TABLE)
{ /* in case of alter temp table send the tracker in OK packet */
thd->session_tracker.state_change.mark_as_changed(thd);
}
if (copy_data_between_tables(thd, table, new_table,
ignore,
order_num, order, &copied, &deleted,
alter_info,
&alter_ctx, online, start_alter_id)) goto err_new_table_cleanup;
} else
{ /* MERGE TABLE */ if (!table->s->tmp_table &&
wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) goto err_new_table_cleanup;
THD_STAGE_INFO(thd, stage_manage_keys);
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
alter_info->keys_onoff); if (trans_commit_stmt(thd) || trans_commit_implicit(thd)) goto err_new_table_cleanup; /* Ensure that the ALTER is binlogged as a DDL */
thd->transaction->stmt.mark_trans_did_ddl();
}
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
if (start_alter_id)
{
DBUG_ASSERT(thd->slave_thread);
if (wait_for_master(thd)) goto err_new_table_cleanup;
} if (table->s->tmp_table != NO_TMP_TABLE)
{ /* Release lock if this is a transactional temporary table */ if (thd->lock)
{ if (thd->locked_tables_mode != LTM_LOCK_TABLES &&
thd->locked_tables_mode != LTM_PRELOCKED_UNDER_LOCK_TABLES)
{ int tmp_error= mysql_unlock_tables(thd, thd->lock);
thd->lock= NULL; if (tmp_error) goto err_new_table_cleanup;
} else
{ /* IfLOCKTABLESlistisnotemptyandcontainsthistable, unlockthetableandremovethetablefromthislist.
*/ if (mysql_lock_remove(thd, thd->lock, table)) goto err_new_table_cleanup;
}
}
/* Remove link to old table and rename the new one */
thd->drop_temporary_table(table, NULL, true); /* Should pass the 'new_name' as we store table name in the cache */ if (thd->rename_temporary_table(new_table, &alter_ctx.new_db,
&alter_ctx.new_name)) goto err_new_table_cleanup;
DBUG_ASSERT(!start_alter_id); // no 2 phase logging for
DBUG_ASSERT(!partial_alter); // temporary table alter
/* We don't replicate alter table statement on temporary tables */ if (!thd->is_binlog_format_row() &&
table_creation_was_logged &&
!binlog_as_create_select)
{ int tmp_error;
thd->binlog_xid= thd->query_id;
ddl_log_update_xid(&ddl_log_state, thd->binlog_xid);
tmp_error= write_bin_log_with_if_exists(thd, true, false, log_if_exists);
thd->binlog_xid= 0; if (tmp_error) goto err_cleanup;
new_table->s->table_creation_was_logged= 1;
} goto end_temporary;
}
/* Remember storage engine name for the new table */
alter_ctx.tmp_storage_engine_name_partitioned=
new_table->file->partition_engine();
alter_ctx.tmp_storage_engine_name.length=
(strmake((char*) alter_ctx.tmp_storage_engine_name.str,
new_table->file->real_table_type(), sizeof(alter_ctx.tmp_storage_engine_buff)-1) -
alter_ctx.tmp_storage_engine_name.str);
debug_crash_here("ddl_log_alter_after_copy"); // Use old table /* Wearenowreadytousethenewtable.Updatethestateinthe ddllogsothatwerecoveryknowthatthenewtableisreadyand incaseofcrashitshouldusethenewoneandlogthequery tothebinarylog.
*/ if (engine_changed)
ddl_log_add_flag(&ddl_log_state, DDL_LOG_FLAG_ALTER_ENGINE_CHANGED);
ddl_log_update_phase(&ddl_log_state, DDL_ALTER_TABLE_PHASE_COPIED);
debug_crash_here("ddl_log_alter_after_log"); // Use new table
THD_STAGE_INFO(thd, stage_rename_result_table);
if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME)) goto err_new_table_cleanup;
/* Now we are the only user. Update the data in EITS tables */
alter_info->apply_statistics_deletes_renames(thd, table);
// Rename the new table to the correct name. if (mysql_rename_table(new_db_type, &alter_ctx.new_db, &alter_ctx.tmp_name,
&alter_ctx.new_db, &alter_ctx.new_alias,
&alter_ctx.tmp_id,
QRMT_DEFAULT | FN_FROM_IS_TMP))
{ // Rename failed, delete the temporary table.
ddl_log_update_phase(&ddl_log_state, DDL_ALTER_TABLE_PHASE_RENAME_FAILED);
(void) quick_rm_table(thd, new_db_type, &alter_ctx.new_db,
&alter_ctx.tmp_name, QRMT_DEFAULT | FN_IS_TMP);
if (!alter_ctx.is_table_renamed() || alter_ctx.fk_error_if_delete_row)
{ // Restore the backup of the original table to the old name.
(void) mysql_rename_table(old_db_type, &alter_ctx.db, &backup_name,
&alter_ctx.db, &alter_ctx.alias, &alter_ctx.id,
FN_FROM_IS_TMP | NO_FK_CHECKS |
(engine_changed ? QRMT_FRM : QRMT_DEFAULT));
} goto err_with_mdl;
}
debug_crash_here("ddl_log_alter_after_rename_to_original");
// Check if we renamed the table and if so update trigger files. if (alter_ctx.is_table_renamed())
{
debug_crash_here("ddl_log_alter_before_rename_triggers"); if (Table_triggers_list::change_table_name(thd, &trigger_param,
&alter_ctx.db,
&alter_ctx.alias,
&alter_ctx.table_name,
&alter_ctx.new_db,
&alter_ctx.new_alias))
{ // Rename succeeded, delete the new table.
(void) quick_rm_table(thd, new_db_type, &alter_ctx.new_db,
&alter_ctx.new_alias, QRMT_DEFAULT); // Restore the backup of the original table to the old name.
(void) mysql_rename_table(old_db_type, &alter_ctx.db, &backup_name,
&alter_ctx.db, &alter_ctx.alias, &alter_ctx.id,
FN_FROM_IS_TMP | NO_FK_CHECKS |
(engine_changed ? QRMT_FRM : QRMT_DEFAULT)); goto err_with_mdl;
}
rename_table_in_stat_tables(thd, &alter_ctx.db, &alter_ctx.alias,
&alter_ctx.new_db, &alter_ctx.new_alias);
debug_crash_here("ddl_log_alter_after_rename_triggers");
}
// ALTER TABLE succeeded, delete the backup of the old table. // a failure to delete isn't an error, as we cannot rollback ALTER anymore
thd->push_internal_handler(&errors_to_warnings);
error_handler_pushed=1;
if (engine_changed)
{ /* the .frm file was removed but not the original table */
quick_rm_table(thd, old_db_type, &alter_ctx.db, &alter_ctx.table_name,
QRMT_HANDLER | (engine_changed ? 0 : FN_IS_TMP));
}
if (start_alter_id)
{ if (!is_reg_table)
{
my_error(ER_INCONSISTENT_SLAVE_TEMP_TABLE, MYF(0), thd->query(),
table_list->db.str, table_list->table_name.str);
DBUG_RETURN(true);
}
if (process_master_state(thd, 0, start_alter_id, if_exists))
DBUG_RETURN(true);
} elseif (!binlog_as_create_select)
{ int tmp_error;
thd->binlog_xid= thd->query_id;
ddl_log_update_xid(&ddl_log_state, thd->binlog_xid);
tmp_error= write_bin_log_with_if_exists(thd, true, false, log_if_exists,
partial_alter);
thd->binlog_xid= 0; if (tmp_error) goto err_cleanup;
}
/* Wehavetoclosetheddllogassoonaspossible,afterbinloggingthe query,forinplacealtertable.
*/
ddl_log_complete(&ddl_log_state); if (inplace_alter_table_committed)
{ /* Signal to storage engine that ddl log is committed */
(*inplace_alter_table_committed)(inplace_alter_table_committed_argument);
inplace_alter_table_committed= 0;
}
// Relay_log_info is too big to put on a stack if (!(rli_buff= thd->alloc(sizeof(Relay_log_info))) ||
!(copy= new (thd->mem_root) Copy_field[to->s->fields]))
DBUG_RETURN(-1);
if (mysql_trans_prepare_alter_copy_data(thd))
{ delete [] copy;
DBUG_RETURN(-1);
}
/* We need external lock before we can disable/enable keys */ if (to->file->ha_external_lock(thd, F_WRLCK))
{ /* Undo call to mysql_trans_prepare_alter_copy_data() */
ha_enable_transaction(thd, TRUE); delete [] copy;
DBUG_RETURN(-1);
}
/* Tell handler that we have values for all columns in the to table */
to->use_all_columns(); /* Add virtual columns to vcol_set to ensure they are updated */ if (to->vfield)
to->mark_virtual_columns_for_write(TRUE); if (init_read_record(&info, thd, from, (SQL_SELECT *) 0, file_sort, 1, 1, FALSE)) goto err;
init_read_record_done= 1;
if (ignore && !alter_ctx->fk_error_if_delete_row)
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
thd->get_stmt_da()->reset_current_row_for_warning(1);
restore_record(to, s->default_values); // Create empty record
to->reset_default_fields();
if (make_versioned)
{
to_row_start->set_notnull();
to_row_start->store_time(&query_start);
to_row_end->set_max();
}
prev_insert_id= to->file->next_insert_id; if (to->default_field)
to->update_default_fields(ignore); if (to->vfield)
to->update_virtual_fields(to->file, VCOL_UPDATE_FOR_WRITE);
/* This will set thd->is_error() if fatal failure */ if (to->verify_constraints(ignore) == VIEW_CHECK_SKIP) continue; if (unlikely(thd->is_error()))
{
error= 1; break;
} if (keep_versioned && to->versioned(VERS_TRX_ID))
to->vers_write= false;
if (to->next_number_field)
{ if (auto_increment_field_copied)
to->auto_increment_field_not_null= TRUE; else
to->next_number_field->reset();
} if (to->s->table_type == TABLE_TYPE_SEQUENCE && found_count == 1)
{
my_error(ER_SEQUENCE_TABLE_HAS_TOO_MANY_ROWS, MYF(0));
error= 1; break;
}
error= to->file->ha_write_row(to->record[0]);
to->auto_increment_field_not_null= FALSE; if (unlikely(error))
{ if (to->file->is_fatal_error(error, HA_CHECK_DUP))
{ /* Not a duplicate key error. */
to->file->print_error(error, MYF(0));
error= 1; break;
} else
{ /* Duplicate key error. */ if (unlikely(alter_ctx->fk_error_if_delete_row))
{ /* Wearetryingtoomitarowfromthetablewhichservesasparent inaforeignkey.Thismighthavebrokenreferentialintegrityso emitanerror.Notethatwecan'tignorethiserrorevenifweare executingALTERIGNORETABLE.IGNOREallowstoskiprows,but doesn'tallowtobreakuniqueorforeignkeyconstraints,
*/
my_error(ER_FK_CANNOT_DELETE_PARENT, MYF(0),
alter_ctx->fk_error_id,
alter_ctx->fk_error_table); break;
}
if (bulk_insert_started && to->file->ha_end_bulk_insert() && error <= 0)
{ /* Give error, if not already given */ if (!thd->is_error())
to->file->print_error(my_errno,MYF(0));
error= 1;
}
bulk_insert_started= 0; if (error <= 0 && !to->s->hlindexes())
{
Abort_on_warning_instant_set save_abort_on_warning(thd, false); int alt_error= to->file->extra(HA_EXTRA_END_COPY); if (alt_error > 0)
{
error= alt_error;
to->file->extra(HA_EXTRA_ABORT_COPY);
copy_data_error_ignore(error, false, to, thd, alter_ctx);
}
}
cleanup_done= 1;
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
/* Finalizethedefault_fieldlist.Seethecommentearlierinthisfunction wherethissamepatternisfollowedforanexplanation.
*/ if (dfield_ptr == to->default_field)
to->default_field= NULL; // No default fields else
*dfield_ptr= NULL; // Mark end of default field pointers
}
rli->relay_log.description_event_for_sql_thread= new Format_description_log_event(4);
// We'll be filling from->record[0] from row events
bitmap_set_all(from->write_set); // We restore bitmaps, because update event is going to mess up with them.
to->default_column_bitmaps();
int lock_error=
thd->mdl_context.upgrade_shared_lock(from->mdl_ticket, MDL_SHARED_NO_WRITE,
(double)thd->variables.lock_wait_timeout); if (!error)
error= lock_error;
if (!error)
{
thd_progress_next_stage(thd);
error= online_alter_read_from_binlog(thd, &rgi, binlog, &found_count);
}
to->pos_in_table_list= NULL; // Safety
DBUG_ASSERT(thd->lex->sql_command == saved_sql_command);
thd->lex->sql_command= saved_sql_command; // Just in case
rli->~Relay_log_info();
} #endif
if (error > 0 && !from->s->tmp_table)
{ /* Abort the operation which invoked extra(HA_EXTRA_BEGIN_COPY)
or extra(HA_EXTRA_BEGIN_ALTER_IGNORE_COPY) */
to->file->extra(HA_EXTRA_ABORT_COPY); /* We are going to drop the temporary table */
to->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
}
DEBUG_SYNC(thd, "copy_data_between_tables_before_reset_backup_lock"); if (backup_reset_alter_copy_lock(thd))
error= 1;
if (unlikely(mysql_trans_commit_alter_copy_data(thd)))
error= 1;
/* Set lock type which is appropriate for ALTER TABLE. */
table_list->lock_type= TL_READ_NO_INSERT; /* Same applies to MDL request. */
table_list->mdl_request.set_type(MDL_SHARED_NO_WRITE); /* hide following tables from open_tables() */
table_list->next_global= NULL;
create_info.init();
create_info.row_type=ROW_TYPE_NOT_USED;
create_info.alter_info= &alter_info;
create_info.recreate_identical_table= 1;
create_info.repair= 1; // Don't write ALTER TABLE to ddl log /* Force alter table to recreate table */
alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
alter_info.partition_flags= thd->lex->alter_info.partition_flags;
if (table_copy && !(alter_info.partition_flags & ALTER_PARTITION_ADMIN))
alter_info.set_requested_algorithm(Alter_info::ALTER_TABLE_ALGORITHM_COPY);
/* Open one table after the other to keep lock time as short as possible. */ for (table= tables; table; table= table->next_local)
{ char table_name_buff[SAFE_NAME_LEN*2+2];
LEX_CSTRING table_name= { table_name_buff, 0};
TABLE *t;
TABLE_LIST *save_next_global;
/* Remember old 'next' pointer and break the list. */
save_next_global= table->next_global;
table->next_global= NULL;
table->lock_type= TL_READ; /* Allow to open real tables only. */
table->required_type= TABLE_TYPE_NORMAL;
if (enf_engine && enf_engine != *new_engine)
{ if (no_substitution)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "NO_ENGINE_SUBSTITUTION");
DBUG_RETURN(TRUE);
} #ifdef WITH_WSREP /* @@enforce_storage_engine is local, if user has used ENGINE=XXXwecan'tallowitinclusterinthis caseasenf_engine!=new_engine.Thisisbecause originalstmtisreplicatedincludingENGINE=XXXand
here */ if ((create_info->used_fields & HA_CREATE_USED_ENGINE) &&
WSREP(thd))
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "ENFORCE_STORAGE_ENGINE");
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_OPTION_PREVENTS_STATEMENT, "Do not use ENGINE=x when @@enforce_storage_engine is set");
if (lex->create_info.resolve_to_charset_collation_context(thd,
thd->charset_collation_context_create_table_in_db(first_table->db.str)))
DBUG_RETURN(true);
if (used_engine)
{ if (resolve_storage_engine_with_error(thd, &lex->create_info.db_type,
lex->create_info.tmp_table()))
DBUG_RETURN(true); // Engine not found, substitution is not allowed
if (!lex->create_info.db_type) // Not found, but substitution is allowed
{
lex->create_info.use_default_db_type(thd);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_WARN_USING_OTHER_HANDLER,
ER_THD(thd, ER_WARN_USING_OTHER_HANDLER),
hton_name(lex->create_info.db_type)->str,
create_table->table_name.str);
}
}
if (lex->tmp_table())
{
status_var_decrement(thd->status_var.com_stat[SQLCOM_CREATE_TABLE]);
status_var_increment(thd->status_var.com_create_tmp_table);
}
#ifdef WITH_WSREP bool wsrep_ctas= false; // If CREATE TABLE AS SELECT and wsrep_on if (WSREP(thd) && (select_lex->item_list.elements || // Only CTAS may be applied not using TOI.
(wsrep_thd_is_applying(thd) && !wsrep_thd_is_toi(thd))))
{
wsrep_ctas= true;
// MDEV-22232: Disable CTAS retry by setting the retry counter to the // threshold value.
thd->wsrep_retry_counter= thd->variables.wsrep_retry_autocommit;
}
// This will be used in THD::decide_logging_format if CTAS
Enable_wsrep_ctas_guard wsrep_ctas_guard(thd, wsrep_ctas); #endif
if (unlikely(thd->is_fatal_error))
{ /* If out of memory when creating a copy of alter_info. */
res= 1; goto end_with_restore_list;
}
/* If: a)weinsideanSPandtherewasNAME_CONSTsubstitution, b)binloggingison(STMTmode), c)welogtheSPasseparatestatements raiseawarning,asitmaycauseproblems (see'NAME_CONSTissues'in'BinaryLoggingofStoredPrograms')
*/ if (thd->query_name_consts && mysql_bin_log.is_open() &&
binlog_format == BINLOG_FORMAT_STMT &&
!mysql_bin_log.is_query_in_union(thd, thd->query_id))
{
List_iterator_fast<Item> it(select_lex->item_list);
Item *item;
uint splocal_refs= 0; /* Count SP local vars in the top-level SELECT list */ while ((item= it++))
{ if (item->get_item_splocal())
splocal_refs++;
} /* IfitdiffersfromnumberofNAME_CONSTsubstitutionapplied, wemayhaveaSOME_FUNC(NAME_CONST())intheSELECTlist, thatmaycauseaproblemwithbinarylog(seeBUG#35383), raiseawarning.
*/ if (splocal_refs != thd->query_name_consts)
push_warning(thd,
Sql_condition::WARN_LEVEL_WARN,
ER_UNKNOWN_ERROR, "Invoked routine ran a statement that may cause problems with " "binary log, see 'NAME_CONST issues' in 'Binary Logging of Stored Programs' " "section of the manual.");
}
res= open_and_lock_tables(thd, create_info, lex->query_tables, TRUE, 0); if (unlikely(res))
{ /* Got error or warning. Set res to 1 if error */ if (!(res= thd->is_error()))
my_ok(thd); // CREATE ... IF NOT EXISTS goto end_with_restore_list;
}
/* Ensure we don't try to create something from which we select from */ if (create_info.or_replace() && !create_info.tmp_table())
{ if (TABLE_LIST *duplicate= unique_table(thd, lex->query_tables,
lex->query_tables->next_global,
CHECK_DUP_FOR_CREATE |
CHECK_DUP_SKIP_TEMP_TABLE))
{
update_non_unique_table_error(lex->query_tables, "CREATE",
duplicate);
res= TRUE; goto end_with_restore_list;
}
}
{ /* Removetargettablefrommainselectandnameresolution context.Thiscan'tbedoneearlierasitwillbreakviewmergingin statementslike"CREATETABLEIFNOTEXISTSexisting_viewSELECT".
*/
lex->unlink_first_table(&link_to_local);
/* Store reference to table in case of LOCK TABLES */
create_info.table= create_table->table;
if (!check_engine(thd, create_table->db.str,
create_table->table_name.str,
&create_info) &&
(!thd->is_binlog_format_row() ||
!create_info.tmp_table()))
{ if (thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE &&
wsrep_check_sequence(thd, lex->create_info.seq_create_info, used_engine))
DBUG_RETURN(true);
WSREP_TO_ISOLATION_BEGIN_ALTER(create_table->db.str, create_table->table_name.str,
first_table, &alter_info, NULL, &create_info)
{
WSREP_WARN("CREATE TABLE isolation failure");
res= true; goto end_with_restore_list;
}
} // check_engine will set db_type to NULL if e.g. TEMPORARY is // not supported by the storage engine, this case is checked // again in mysql_create_table
create_info.db_type= orig_ht;
} #endif/* WITH_WSREP */
/* Regular CREATE TABLE */
res= mysql_create_table(thd, create_table, &create_info, &alter_info);
} if (!res)
{ /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */ if (create_info.tmp_table())
thd->variables.option_bits|= OPTION_BINLOG_THIS_TRX; /* in case of create temp tables if @@session_track_state_change is
ON then send session state notification in OK packet */ if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
{
thd->session_tracker.state_change.mark_as_changed(thd);
}
my_ok(thd);
}
}
if (default_cscl.is_empty())
default_table_charset= ctx.collate_default().charset_info(); else
{ // Make sure we don't do double resolution in direct SQL execution
DBUG_ASSERT(!default_table_charset ||
thd->stmt_arena->is_stmt_execute() ||
thd->stmt_arena->state == Query_arena::STMT_INITIALIZED_FOR_SP); if (!(default_table_charset=
default_cscl.resolved_to_context(thd,
thd->variables.character_set_collations, ctx))) returntrue;
}
if (convert_cscl.is_empty())
alter_table_convert_to_charset= NULL; else
{ // Make sure we don't do double resolution in direct SQL execution
DBUG_ASSERT(!alter_table_convert_to_charset ||
thd->stmt_arena->is_stmt_execute() ||
thd->stmt_arena->state == Query_arena::STMT_INITIALIZED_FOR_SP); if (!(alter_table_convert_to_charset=
convert_cscl.resolved_to_context(thd,
thd->variables.character_set_collations, ctx))) returntrue;
} returnfalse;
}
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.3.868Bemerkung:
(vorverarbeitet am 2026-10-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.