724
bool alter_table(Session *session,
727
TableIdentifier &original_table_identifier,
728
HA_CREATE_INFO *create_info,
729
message::Table &create_proto,
730
TableList *table_list,
731
AlterInfo *alter_info,
775
static bool internal_alter_table(Session *session,
777
TableIdentifier &original_table_identifier,
778
TableIdentifier &new_table_identifier,
779
HA_CREATE_INFO *create_info,
780
message::Table &create_proto,
781
TableList *table_list,
782
AlterInfo *alter_info,
737
787
Table *new_table= NULL;
738
Table *name_lock= NULL;
741
789
char tmp_name[80];
742
790
char old_name[32];
745
const char *new_alias;
746
791
ha_rows copied= 0;
747
792
ha_rows deleted= 0;
748
plugin::StorageEngine *old_db_type;
749
plugin::StorageEngine *new_db_type;
750
plugin::StorageEngine *save_old_db_type;
794
message::Table *original_table_definition= table->s->getTableProto();
753
796
session->set_proc_info("init");
756
Assign variables table_name, new_name, db, new_db, path
757
to simplify further comparisons: we want to see if it's a RENAME
758
later just by comparing the pointers, avoiding the need for strcmp.
760
table_name= table_list->table_name;
762
if (! new_db || ! my_strcasecmp(table_alias_charset, new_db, db))
765
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
767
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
768
return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
772
If this is just a rename of a view, short cut to the
773
following scenario: 1) lock LOCK_open 2) do a RENAME
775
This is a copy-paste added to make sure
776
ALTER (sic:) Table .. RENAME works for views. ALTER VIEW is handled
777
as an independent branch in mysql_execute_command. The need
778
for a copy-paste arose because the main code flow of ALTER Table
779
... RENAME tries to use openTableLock, which does not work for views
780
(openTableLock was never modified to merge table lists of child tables
781
into the main table list, like open_tables does).
782
This code is wrong and will be removed, please do not copy.
785
if (not (table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
788
798
table->use_all_columns();
790
bool error_on_rename= false;
792
/* Check that we are not trying to rename to an existing table */
795
char new_alias_buff[FN_REFLEN];
796
char lower_case_table_name[FN_REFLEN];
798
strcpy(lower_case_table_name, new_name);
799
strcpy(new_alias_buff, new_name);
800
new_alias= new_alias_buff;
802
my_casedn_str(files_charset_info, lower_case_table_name);
803
new_alias= new_name; // Create lower case table name
804
my_casedn_str(files_charset_info, new_name);
807
not my_strcasecmp(table_alias_charset, lower_case_table_name, table_name))
810
Source and destination table names are equal: make later check
813
new_alias= new_name= table_name;
817
TableIdentifier identifier(new_db, lower_case_table_name);
819
if (table->s->tmp_table != STANDARD_TABLE)
822
if (session->find_temporary_table(identifier))
824
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), lower_case_table_name);
830
if (session->lock_table_name_if_not_cached(new_db, new_name, &name_lock))
835
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
839
if (plugin::StorageEngine::doesTableExist(*session, identifier))
841
/* Table will be closed by Session::executeCommand() */
842
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
843
error_on_rename= true;
800
plugin::StorageEngine *new_engine;
801
plugin::StorageEngine *original_engine;
803
original_engine= table->s->getEngine();
805
if (not create_info->db_type)
807
create_info->db_type= original_engine;
809
new_engine= create_info->db_type;
812
create_proto.set_schema(new_table_identifier.getSchemaName().c_str());
814
if (new_table_identifier.isTmp())
816
create_proto.set_type(message::Table::TEMPORARY);
850
new_alias= table_name;
851
new_name= table_name;
854
TableIdentifier new_table_as_replacement(new_db, new_alias);
856
if (not error_on_rename)
858
old_db_type= table->s->db_type();
859
if (not create_info->db_type)
861
create_info->db_type= old_db_type;
864
create_proto.set_schema(new_db);
866
if (table->s->tmp_table != STANDARD_TABLE)
868
create_proto.set_type(message::Table::TEMPORARY);
872
create_proto.set_type(message::Table::STANDARD);
875
new_db_type= create_info->db_type;
878
@todo Have a check on the table definition for FK in the future
879
to remove the need for the cursor. (aka can_switch_engines())
881
if (new_db_type != old_db_type &&
882
not table->cursor->can_switch_engines())
885
my_error(ER_ROW_IS_REFERENCED, MYF(0));
889
if (create_info->row_type == ROW_TYPE_NOT_USED)
891
message::Table::TableOptions *table_options;
892
table_options= create_proto.mutable_options();
894
create_info->row_type= table->s->row_type;
895
table_options->set_row_type((message::Table_TableOptions_RowType)table->s->row_type);
898
if (old_db_type->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
899
new_db_type->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
901
my_error(ER_ILLEGAL_HA, MYF(0), table_name);
905
session->set_proc_info("setup");
908
* test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
820
create_proto.set_type(message::Table::STANDARD);
824
@todo Have a check on the table definition for FK in the future
825
to remove the need for the cursor. (aka can_switch_engines())
827
if (new_engine != original_engine &&
828
not table->cursor->can_switch_engines())
831
my_error(ER_ROW_IS_REFERENCED, MYF(0));
836
if (original_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
837
new_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
839
my_error(ER_ILLEGAL_HA, MYF(0), new_table_identifier.getSQLPath().c_str());
844
if (create_info->row_type == ROW_TYPE_NOT_USED)
846
message::Table::TableOptions *table_options;
847
table_options= create_proto.mutable_options();
849
create_info->row_type= table->s->row_type;
850
table_options->set_row_type(original_table_definition->options().row_type());
853
session->set_proc_info("setup");
856
* test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
911
862
tmp.reset(ALTER_RENAME);
912
863
tmp.reset(ALTER_KEYS_ONOFF);
913
864
tmp&= alter_info->flags;
914
866
if (! (tmp.any()) && ! table->s->tmp_table) // no need to touch frm
916
868
switch (alter_info->keys_onoff)
1020
session->unlink_open_table(name_lock);
1022
968
pthread_mutex_unlock(&LOCK_open);
1023
969
table_list->table= NULL;
1028
/* We have to do full alter table. */
1029
new_db_type= create_info->db_type;
1031
if (mysql_prepare_alter_table(session, table, create_info, create_proto, alter_info))
1034
set_table_default_charset(create_info, db);
1036
alter_info->build_method= HA_BUILD_OFFLINE;
1038
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1040
/* Safety fix for innodb */
1041
my_casedn_str(files_charset_info, tmp_name);
1043
/* Create a temporary table with the new format */
1045
@note we make an internal temporary table unless the table is a temporary table. In last
1046
case we just use it as is. Neither of these tables require locks in order to be
1049
TableIdentifier new_table_as_temporary(new_db,
1051
create_proto.type() != message::Table::TEMPORARY ? INTERNAL_TMP_TABLE :
1054
error= create_temporary_table(session, new_table_as_temporary, create_info, create_proto, alter_info);
1059
/* Open the table so we need to copy the data to it. */
1060
new_table= open_alter_table(session, table, new_db, tmp_name);
1062
if (new_table == NULL)
1065
/* Copy the data if necessary. */
975
/* We have to do full alter table. */
976
new_engine= create_info->db_type;
978
if (mysql_prepare_alter_table(session, table, create_info, create_proto, alter_info))
983
set_table_default_charset(create_info, new_table_identifier.getSchemaName().c_str());
985
alter_info->build_method= HA_BUILD_OFFLINE;
987
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
989
/* Create a temporary table with the new format */
991
@note we make an internal temporary table unless the table is a temporary table. In last
992
case we just use it as is. Neither of these tables require locks in order to be
995
TableIdentifier new_table_as_temporary(original_table_identifier.getSchemaName(),
997
create_proto.type() != message::Table::TEMPORARY ? INTERNAL_TMP_TABLE :
1000
error= create_temporary_table(session, new_table_as_temporary, create_info, create_proto, alter_info);
1007
/* Open the table so we need to copy the data to it. */
1008
new_table= open_alter_table(session, table, new_table_as_temporary);
1012
quick_rm_table(*session, new_table_as_temporary);
1016
/* Copy the data if necessary. */
1066
1018
session->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
1067
1019
session->cuted_fields= 0L;
1068
1020
session->set_proc_info("copy to tmp table");
1069
1021
copied= deleted= 0;
1073
1023
/* We don't want update TIMESTAMP fields during ALTER Table. */
1074
1024
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
1075
1025
new_table->next_number_field= new_table->found_next_number_field;
1087
1037
/* We must not ignore bad input! */
1088
1038
session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
1090
if (table->s->tmp_table != STANDARD_TABLE)
1092
/* We changed a temporary table */
1096
/* Close lock if this is a transactional table */
1099
mysql_unlock_tables(session, session->lock);
1103
/* Remove link to old table and rename the new one */
1104
session->close_temporary_table(table);
1106
/* Should pass the 'new_name' as we store table name in the cache */
1107
TableIdentifier alter_identifier(new_db, new_name);
1108
if (new_table->renameAlterTemporaryTable(alter_identifier))
1116
Close the intermediate table that will be the new table.
1117
Note that MERGE tables do not have their children attached here.
1119
new_table->intern_close_table();
1123
pthread_mutex_lock(&LOCK_open); /* ALTER TABLE */
1127
TableIdentifier identifier(new_db, tmp_name, INTERNAL_TMP_TABLE);
1128
quick_rm_table(*session, identifier);
1129
pthread_mutex_unlock(&LOCK_open);
1134
Data is copied. Now we:
1135
1) Wait until all other threads close old version of table.
1136
2) Close instances of table open by this thread and replace them
1137
with exclusive name-locks.
1138
3) Rename the old table to a temp name, rename the new one to the
1140
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1141
we reopen new version of table.
1142
5) Write statement to the binary log.
1143
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1144
remove name-locks from list of open tables and table cache.
1145
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1146
call to remove name-locks from table cache and list of open table.
1149
session->set_proc_info("rename result table");
1151
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1153
my_casedn_str(files_charset_info, old_name);
1155
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1156
session->close_data_files_and_morph_locks(db, table_name);
1159
save_old_db_type= old_db_type;
1162
This leads to the storage engine (SE) not being notified for renames in
1163
mysql_rename_table(), because we just juggle with the FRM and nothing
1164
more. If we have an intermediate table, then we notify the SE that
1165
it should become the actual table. Later, we will recycle the old table.
1166
However, in case of ALTER Table RENAME there might be no intermediate
1167
table. This is when the old and new tables are compatible, according to
1168
compare_table(). Then, we need one additional call to
1170
TableIdentifier original_table_to_drop(db, old_name, TEMP_TABLE);
1171
if (mysql_rename_table(old_db_type, original_table_identifier, original_table_to_drop, FN_TO_IS_TMP))
1174
TableIdentifier identifier(new_db, tmp_name, INTERNAL_TMP_TABLE);
1175
quick_rm_table(*session, identifier);
1179
if (mysql_rename_table(new_db_type, new_table_as_temporary, new_table_as_replacement, FN_FROM_IS_TMP) != 0)
1181
/* Try to get everything back. */
1184
quick_rm_table(*session, new_table_as_replacement);
1186
quick_rm_table(*session, new_table_as_temporary);
1188
mysql_rename_table(old_db_type, original_table_to_drop, original_table_identifier, FN_FROM_IS_TMP);
1192
quick_rm_table(*session, original_table_to_drop);
1199
An error happened while we were holding exclusive name-lock on table
1200
being altered. To be safe under LOCK TABLES we should remove placeholders
1201
from list of open tables list and table cache.
1203
session->unlink_open_table(table);
1205
session->unlink_open_table(name_lock);
1206
pthread_mutex_unlock(&LOCK_open);
1211
pthread_mutex_unlock(&LOCK_open);
1213
session->set_proc_info("end");
1215
write_bin_log(session, session->query.c_str());
1216
table_list->table= NULL;
1220
* Field::store() may have called my_error(). If this is
1221
* the case, we must not send an ok packet, since
1222
* Diagnostics_area::is_set() will fail an assert.
1224
if (! session->is_error())
1226
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
1227
(ulong) (copied + deleted), (ulong) deleted,
1228
(ulong) session->cuted_fields);
1229
session->my_ok(copied + deleted, 0, 0L, tmp_name);
1230
session->some_tables_deleted= 0;
1235
/* my_error() was called. Return true (which means error...) */
1242
/* close_temporary_table() frees the new_table pointer. */
1243
session->close_temporary_table(new_table);
1247
TableIdentifier tmp_identifier(new_db, tmp_name, INTERNAL_TMP_TABLE);
1248
quick_rm_table(*session, tmp_identifier);
1254
No default value was provided for a DATE/DATETIME field, the
1255
current sql_mode doesn't allow the '0000-00-00' value and
1256
the table to be altered isn't empty.
1259
if (alter_info->error_if_not_empty && session->row_count)
1041
/* Now we need to resolve what just happened with the data copy. */
1261
const char *f_val= 0;
1262
enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
1264
switch (alter_info->datetime_field->sql_type)
1047
No default value was provided for a DATE/DATETIME field, the
1048
current sql_mode doesn't allow the '0000-00-00' value and
1049
the table to be altered isn't empty.
1052
if (alter_info->error_if_not_empty && session->row_count)
1054
const char *f_val= 0;
1055
enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
1057
switch (alter_info->datetime_field->sql_type)
1266
1059
case DRIZZLE_TYPE_DATE:
1267
1060
f_val= "0000-00-00";
1268
1061
t_type= DRIZZLE_TIMESTAMP_DATE;
1275
1068
/* Shouldn't get here. */
1278
bool save_abort_on_warning= session->abort_on_warning;
1279
session->abort_on_warning= true;
1280
make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1281
f_val, internal::strlength(f_val), t_type,
1282
alter_info->datetime_field->field_name);
1283
session->abort_on_warning= save_abort_on_warning;
1288
pthread_mutex_lock(&LOCK_open); /* ALTER TABLe */
1289
session->unlink_open_table(name_lock);
1071
bool save_abort_on_warning= session->abort_on_warning;
1072
session->abort_on_warning= true;
1073
make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1074
f_val, internal::strlength(f_val), t_type,
1075
alter_info->datetime_field->field_name);
1076
session->abort_on_warning= save_abort_on_warning;
1079
if (original_table_identifier.isTmp())
1083
/* close_temporary_table() frees the new_table pointer. */
1084
session->close_temporary_table(new_table);
1088
quick_rm_table(*session, new_table_as_temporary);
1098
Close the intermediate table that will be the new table.
1099
Note that MERGE tables do not have their children attached here.
1101
new_table->intern_close_table();
1105
pthread_mutex_lock(&LOCK_open); /* ALTER TABLE */
1107
quick_rm_table(*session, new_table_as_temporary);
1108
pthread_mutex_unlock(&LOCK_open);
1113
// Temporary table and success
1114
else if (original_table_identifier.isTmp())
1116
/* Close lock if this is a transactional table */
1119
mysql_unlock_tables(session, session->lock);
1123
/* Remove link to old table and rename the new one */
1124
session->close_temporary_table(table);
1126
/* Should pass the 'new_name' as we store table name in the cache */
1127
if (new_table->renameAlterTemporaryTable(new_table_identifier))
1131
/* close_temporary_table() frees the new_table pointer. */
1132
session->close_temporary_table(new_table);
1136
quick_rm_table(*session, new_table_as_temporary);
1142
// Normal table success
1148
Close the intermediate table that will be the new table.
1149
Note that MERGE tables do not have their children attached here.
1151
new_table->intern_close_table();
1155
pthread_mutex_lock(&LOCK_open); /* ALTER TABLE */
1158
Data is copied. Now we:
1159
1) Wait until all other threads close old version of table.
1160
2) Close instances of table open by this thread and replace them
1161
with exclusive name-locks.
1162
3) Rename the old table to a temp name, rename the new one to the
1164
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1165
we reopen new version of table.
1166
5) Write statement to the binary log.
1167
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1168
remove name-locks from list of open tables and table cache.
1169
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1170
call to remove name-locks from table cache and list of open table.
1173
session->set_proc_info("rename result table");
1175
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1177
my_casedn_str(files_charset_info, old_name);
1179
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1180
session->close_data_files_and_morph_locks(original_table_identifier);
1185
This leads to the storage engine (SE) not being notified for renames in
1186
mysql_rename_table(), because we just juggle with the FRM and nothing
1187
more. If we have an intermediate table, then we notify the SE that
1188
it should become the actual table. Later, we will recycle the old table.
1189
However, in case of ALTER Table RENAME there might be no intermediate
1190
table. This is when the old and new tables are compatible, according to
1191
compare_table(). Then, we need one additional call to
1193
TableIdentifier original_table_to_drop(original_table_identifier.getSchemaName(),
1194
old_name, TEMP_TABLE);
1196
if (mysql_rename_table(original_engine, original_table_identifier, original_table_to_drop, FN_TO_IS_TMP))
1199
quick_rm_table(*session, new_table_as_temporary);
1203
if (mysql_rename_table(new_engine, new_table_as_temporary, new_table_identifier, FN_FROM_IS_TMP) != 0)
1205
/* Try to get everything back. */
1208
quick_rm_table(*session, new_table_identifier);
1210
quick_rm_table(*session, new_table_as_temporary);
1212
mysql_rename_table(original_engine, original_table_to_drop, original_table_identifier, FN_FROM_IS_TMP);
1216
quick_rm_table(*session, original_table_to_drop);
1223
An error happened while we were holding exclusive name-lock on table
1224
being altered. To be safe under LOCK TABLES we should remove placeholders
1225
from list of open tables list and table cache.
1227
session->unlink_open_table(table);
1228
pthread_mutex_unlock(&LOCK_open);
1290
1234
pthread_mutex_unlock(&LOCK_open);
1236
session->set_proc_info("end");
1238
write_bin_log(session, session->query.c_str());
1239
table_list->table= NULL;
1243
* Field::store() may have called my_error(). If this is
1244
* the case, we must not send an ok packet, since
1245
* Diagnostics_area::is_set() will fail an assert.
1247
if (session->is_error())
1249
/* my_error() was called. Return true (which means error...) */
1253
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
1254
(ulong) (copied + deleted), (ulong) deleted,
1255
(ulong) session->cuted_fields);
1256
session->my_ok(copied + deleted, 0, 0L, tmp_name);
1257
session->some_tables_deleted= 0;
1262
bool alter_table(Session *session,
1263
TableIdentifier &original_table_identifier,
1264
TableIdentifier &new_table_identifier,
1265
HA_CREATE_INFO *create_info,
1266
message::Table &create_proto,
1267
TableList *table_list,
1268
AlterInfo *alter_info,
1276
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
1278
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
1279
return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
1282
session->set_proc_info("init");
1284
if (not (table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
1287
session->set_proc_info("gained write lock on table");
1290
Check that we are not trying to rename to an existing table,
1291
if one existed we get a lock, if we can't we error.
1294
Table *name_lock= NULL;
1296
if (not lockTableIfDifferent(*session, original_table_identifier, new_table_identifier, name_lock))
1301
error= internal_alter_table(session,
1303
original_table_identifier,
1304
new_table_identifier,
1315
pthread_mutex_lock(&LOCK_open); /* ALTER TABLe */
1316
session->unlink_open_table(name_lock);
1317
pthread_mutex_unlock(&LOCK_open);
1295
1323
/* alter_table */